mirror of
https://github.com/linuxserver/Heimdall.git
synced 2026-02-24 05:30:33 +09:00
Compare commits
718 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1750da1345 | ||
|
|
398df75865 | ||
|
|
41c2983312 | ||
|
|
bd3b882b3a | ||
|
|
e52bc9c6b2 | ||
|
|
a16233ee10 | ||
|
|
5b177f1127 | ||
|
|
f7633b6a5f | ||
|
|
d58e6cb560 | ||
|
|
87fe9c1771 | ||
|
|
95d9e9edb9 | ||
|
|
f7b2c51f9d | ||
|
|
72c70e27f2 | ||
|
|
becbe5ab96 | ||
|
|
f5bce95808 | ||
|
|
1e2b807e05 | ||
|
|
ed3dbf2f14 | ||
|
|
1e35f83fed | ||
|
|
8499d100ff | ||
|
|
bdeae6a722 | ||
|
|
4c63b66dbf | ||
|
|
371f52f92e | ||
|
|
6daaf94974 | ||
|
|
b8e5a22648 | ||
|
|
e821edf01a | ||
|
|
188316df47 | ||
|
|
dd14ce8738 | ||
|
|
d8e4053ce4 | ||
|
|
f73b78f292 | ||
|
|
96ec1e0b08 | ||
|
|
1904d9d910 | ||
|
|
beb2851f4a | ||
|
|
645a0bc7fe | ||
|
|
ef73918098 | ||
|
|
06a23c70af | ||
|
|
323a6e17c7 | ||
|
|
0ca07c9698 | ||
|
|
fbb21d2885 | ||
|
|
b6741c8ff0 | ||
|
|
7fdca02af7 | ||
|
|
271100c25b | ||
|
|
cfecce6100 | ||
|
|
d71341df7a | ||
|
|
ac851f5a02 | ||
|
|
d2a8b7af48 | ||
|
|
4d7a86fbf7 | ||
|
|
87a3af3dbf | ||
|
|
79c76b9f50 | ||
|
|
d7742df802 | ||
|
|
736222e173 | ||
|
|
047ffb0b55 | ||
|
|
505d17cf57 | ||
|
|
71c2da160d | ||
|
|
3487b9e479 | ||
|
|
7cdf315d78 | ||
|
|
a1812a962c | ||
|
|
b97cab34b0 | ||
|
|
3426450b3c | ||
|
|
75804f4624 | ||
|
|
23f757e06f | ||
|
|
fabd704bab | ||
|
|
c16fbae963 | ||
|
|
348759b9ad | ||
|
|
d961aeb19b | ||
|
|
987a9c03b0 | ||
|
|
d17fb04983 | ||
|
|
b07918d751 | ||
|
|
f9a19fce91 | ||
|
|
1b71e80d52 | ||
|
|
9fac11cb77 | ||
|
|
a94fb108fa | ||
|
|
f51893b2d6 | ||
|
|
a4b32dcafd | ||
|
|
862f870303 | ||
|
|
869cfd34ab | ||
|
|
9e67b7c72e | ||
|
|
d0e3a2faf5 | ||
|
|
a5b7f10809 | ||
|
|
698665176c | ||
|
|
1bd65222e4 | ||
|
|
61a5a1a8b0 | ||
|
|
e51cdd7f7a | ||
|
|
a626222ff3 | ||
|
|
af68a45a3d | ||
|
|
7969df9344 | ||
|
|
67bc656325 | ||
|
|
b5baf0d606 | ||
|
|
32964e9045 | ||
|
|
27a667675a | ||
|
|
9a221f47bf | ||
|
|
8d2fbc5599 | ||
|
|
84ebe6587d | ||
|
|
89a71a18da | ||
|
|
05dd7a090b | ||
|
|
3a9bdd2c43 | ||
|
|
0292e9976e | ||
|
|
365de9512f | ||
|
|
e857023903 | ||
|
|
c058e1a452 | ||
|
|
7f42967b67 | ||
|
|
994961de54 | ||
|
|
049d20536c | ||
|
|
c9c8171a52 | ||
|
|
e7a6ac5a75 | ||
|
|
3a372107ba | ||
|
|
493374de65 | ||
|
|
c43fc929f7 | ||
|
|
895d5f2ebe | ||
|
|
cb4768e2cf | ||
|
|
6ca4bfb9ee | ||
|
|
1f7de03d90 | ||
|
|
861d287750 | ||
|
|
e2cc32fd0a | ||
|
|
762df25c45 | ||
|
|
0b114e7dc1 | ||
|
|
981876c43c | ||
|
|
7fe9c477e3 | ||
|
|
5b3a7f4e02 | ||
|
|
60e20c4023 | ||
|
|
9e1bb6c075 | ||
|
|
9c05d0d803 | ||
|
|
3d1393c0b3 | ||
|
|
9914fdb111 | ||
|
|
9b24c9f1b5 | ||
|
|
81b8c646d2 | ||
|
|
f734832e0f | ||
|
|
1bde11b30b | ||
|
|
9e80c3fe40 | ||
|
|
f272dd13ce | ||
|
|
9f26de89a4 | ||
|
|
e23964ebad | ||
|
|
d0584ac941 | ||
|
|
1410c41f48 | ||
|
|
5f524563cf | ||
|
|
3d181623c3 | ||
|
|
1919dbfd96 | ||
|
|
8e1615ac5f | ||
|
|
7966f07fdb | ||
|
|
ac8fe7012b | ||
|
|
51d89dae82 | ||
|
|
ef21ac0fe7 | ||
|
|
02697687cc | ||
|
|
fd2f7f27a6 | ||
|
|
21b1ef5e4b | ||
|
|
e452d3b5f6 | ||
|
|
1419882455 | ||
|
|
d79202ed87 | ||
|
|
aa05c947a9 | ||
|
|
eb69ea05fa | ||
|
|
244b0998f9 | ||
|
|
1f608b1c21 | ||
|
|
7d6df3843b | ||
|
|
dd4b94ba71 | ||
|
|
edb9397a47 | ||
|
|
66815a8487 | ||
|
|
5ee19bceb6 | ||
|
|
deba7d0279 | ||
|
|
38e93d33f1 | ||
|
|
f182f305fc | ||
|
|
03c675ed57 | ||
|
|
3916b2d4dc | ||
|
|
698a7a9bbc | ||
|
|
9954d1b6bf | ||
|
|
a98b981efe | ||
|
|
dd2ca62eaf | ||
|
|
dc2a42ad6d | ||
|
|
b5b25458db | ||
|
|
ac4bbceb2f | ||
|
|
4980bfab12 | ||
|
|
63e0d07d50 | ||
|
|
2b76520e3a | ||
|
|
6631b8a23b | ||
|
|
04d34017c1 | ||
|
|
6dcbcb452e | ||
|
|
7c74b3bb13 | ||
|
|
b76a9ee118 | ||
|
|
40da649b10 | ||
|
|
cd64d762e7 | ||
|
|
b91c52820a | ||
|
|
1204ffd306 | ||
|
|
978267dd14 | ||
|
|
f935fd94c6 | ||
|
|
fb2428e21b | ||
|
|
e36a126c01 | ||
|
|
b186978624 | ||
|
|
49773d7654 | ||
|
|
53c03751a1 | ||
|
|
9d2908449a | ||
|
|
caf92bcf6d | ||
|
|
cbef469e02 | ||
|
|
a6bfc1d76c | ||
|
|
0446a74de9 | ||
|
|
1a14079b39 | ||
|
|
d9c1919ddc | ||
|
|
f42ac0c5ba | ||
|
|
c073929895 | ||
|
|
02df7844a4 | ||
|
|
e43aba0111 | ||
|
|
ac7446ffe6 | ||
|
|
e45d3ca6ec | ||
|
|
603550a453 | ||
|
|
4463ef4a9a | ||
|
|
49b8dc0079 | ||
|
|
ab83c3a551 | ||
|
|
98c6093674 | ||
|
|
e1f51521bf | ||
|
|
e85bc98dcc | ||
|
|
4ba52baa5c | ||
|
|
a82077b4de | ||
|
|
b8f04f3d11 | ||
|
|
e91f65f833 | ||
|
|
575ab9be2d | ||
|
|
64071bb60f | ||
|
|
44621a1a61 | ||
|
|
c56043e1f9 | ||
|
|
e8e4cbfd41 | ||
|
|
4b2bbe0614 | ||
|
|
9adfa14e62 | ||
|
|
067f82b632 | ||
|
|
e24e7979be | ||
|
|
c7c2b6e6f2 | ||
|
|
96798963d6 | ||
|
|
75508a81ef | ||
|
|
f7f4efadb7 | ||
|
|
4cc80b98db | ||
|
|
b07efaa7d0 | ||
|
|
7ba8ea6dd4 | ||
|
|
479461821f | ||
|
|
d25aea38fb | ||
|
|
0067502b37 | ||
|
|
d321af6085 | ||
|
|
b30f1730e4 | ||
|
|
7a02986982 | ||
|
|
a4107cba25 | ||
|
|
ba187aa345 | ||
|
|
b400cef734 | ||
|
|
03b72b8d2e | ||
|
|
0c7e20dee0 | ||
|
|
aa42c71a06 | ||
|
|
041c0b81a3 | ||
|
|
fe6776ee9d | ||
|
|
125b9f4160 | ||
|
|
488fee7b4b | ||
|
|
4fba596909 | ||
|
|
af04781830 | ||
|
|
2507cda94c | ||
|
|
21c1401859 | ||
|
|
4351f55225 | ||
|
|
d1956c4e88 | ||
|
|
d76d056ed1 | ||
|
|
e081cc31a2 | ||
|
|
88153b0e32 | ||
|
|
2b2d51cb6f | ||
|
|
abd8c7227d | ||
|
|
50d6dc7b71 | ||
|
|
b4a1ecc305 | ||
|
|
540bead0db | ||
|
|
6e9f25d680 | ||
|
|
268afe7006 | ||
|
|
7b9d3f0ec6 | ||
|
|
de116030bc | ||
|
|
4fb59385b7 | ||
|
|
40d6808067 | ||
|
|
3572bd8068 | ||
|
|
380a0e8623 | ||
|
|
4f6a0cb7c6 | ||
|
|
56cce8233b | ||
|
|
af8afcf931 | ||
|
|
7f997d60cd | ||
|
|
d45f5a805e | ||
|
|
fc9c624509 | ||
|
|
33372509eb | ||
|
|
bca0b02925 | ||
|
|
24995135e6 | ||
|
|
c1e4103edd | ||
|
|
6eda423156 | ||
|
|
7dc72d3519 | ||
|
|
907c22179b | ||
|
|
cdafbab7b1 | ||
|
|
e0064504e7 | ||
|
|
b22117dd01 | ||
|
|
c88efa8dbc | ||
|
|
7d060ff803 | ||
|
|
d5f8b6aae0 | ||
|
|
2416993c5e | ||
|
|
494165a03a | ||
|
|
88e607533c | ||
|
|
035d2f9209 | ||
|
|
53903daa87 | ||
|
|
567994be1a | ||
|
|
32fa27337a | ||
|
|
e1bb7646ac | ||
|
|
108b636def | ||
|
|
4abb14bf54 | ||
|
|
f8f96593c1 | ||
|
|
cb21b0f8f1 | ||
|
|
4c8c5fa27f | ||
|
|
6093119dde | ||
|
|
15755a3fd1 | ||
|
|
0213c81e0d | ||
|
|
c47f296f17 | ||
|
|
75133474f7 | ||
|
|
ddbe171f3a | ||
|
|
12e109f82c | ||
|
|
e095589172 | ||
|
|
d0293c785b | ||
|
|
aa351e31bf | ||
|
|
aceed3d13b | ||
|
|
10b70d4a09 | ||
|
|
cb9e014cf3 | ||
|
|
99017d834e | ||
|
|
fb73f5ca24 | ||
|
|
4369f1aeda | ||
|
|
6501aacb1b | ||
|
|
c3da17befc | ||
|
|
46bb073001 | ||
|
|
e8b47776ce | ||
|
|
6941fd3e2d | ||
|
|
f5937879df | ||
|
|
93877b7025 | ||
|
|
6612631cc3 | ||
|
|
30c3079a90 | ||
|
|
e86e681c53 | ||
|
|
48f72652da | ||
|
|
a3f7bafedb | ||
|
|
d30d610042 | ||
|
|
882e406266 | ||
|
|
45d421256c | ||
|
|
a2f20fc18f | ||
|
|
988364cb7c | ||
|
|
a3816ed8a1 | ||
|
|
d48805ee2c | ||
|
|
e820b81259 | ||
|
|
8b1046ce17 | ||
|
|
a138b65842 | ||
|
|
c344de3f04 | ||
|
|
427659a897 | ||
|
|
a6543970e7 | ||
|
|
399ea088dc | ||
|
|
3f87833e52 | ||
|
|
6dcb77023c | ||
|
|
4d37135bdf | ||
|
|
d109047fa5 | ||
|
|
b6112501e2 | ||
|
|
0663e236b4 | ||
|
|
f25cea1749 | ||
|
|
03e16415aa | ||
|
|
9a55e05943 | ||
|
|
c06fa4eab6 | ||
|
|
5575b082ea | ||
|
|
1c6da858bc | ||
|
|
f0a14641c1 | ||
|
|
c6d07cd8a4 | ||
|
|
df9f07faf4 | ||
|
|
a3dcc278d7 | ||
|
|
5de473fa44 | ||
|
|
763c1545a6 | ||
|
|
ecde7a0f32 | ||
|
|
7fc5e0abb5 | ||
|
|
06a655ac0c | ||
|
|
875ddaa834 | ||
|
|
030fccbb50 | ||
|
|
908f70d90a | ||
|
|
8724ced531 | ||
|
|
aa1a3a95ca | ||
|
|
0767dc075e | ||
|
|
c8a6c89036 | ||
|
|
cafe386cc4 | ||
|
|
0184c9695b | ||
|
|
19536edf28 | ||
|
|
045e4a20fa | ||
|
|
6cb8487a52 | ||
|
|
c39e9aa13f | ||
|
|
0203440b06 | ||
|
|
7f7bf60456 | ||
|
|
e8673634bc | ||
|
|
53e52c93ee | ||
|
|
c239c0ea5a | ||
|
|
7142f755f5 | ||
|
|
9fbc8dc1f9 | ||
|
|
d3819a6a88 | ||
|
|
6e93ed8e5f | ||
|
|
98543d49a9 | ||
|
|
9195eead27 | ||
|
|
e5b384736d | ||
|
|
4def720d1a | ||
|
|
2a0404ea17 | ||
|
|
6d22c4f02e | ||
|
|
24ac12da65 | ||
|
|
3f19882df8 | ||
|
|
dd54c16c1f | ||
|
|
223e9289dc | ||
|
|
2e301bdd51 | ||
|
|
e3ec7de23a | ||
|
|
18ec208381 | ||
|
|
8666daa07d | ||
|
|
926a9bdb03 | ||
|
|
fc2d837a2c | ||
|
|
3f69ccab99 | ||
|
|
b6ee82ee52 | ||
|
|
da1eb859a9 | ||
|
|
2b5269b823 | ||
|
|
6c8eeb0ced | ||
|
|
c5e0f3abc8 | ||
|
|
c6dbe22c57 | ||
|
|
51776e2aa3 | ||
|
|
c9d24607f6 | ||
|
|
46f7a3d4f3 | ||
|
|
56cf450c89 | ||
|
|
38c350b020 | ||
|
|
1f46040f1b | ||
|
|
63b95319cd | ||
|
|
a25d92be9e | ||
|
|
a161210a4a | ||
|
|
24469eb2fa | ||
|
|
a93fb49875 | ||
|
|
08d7cdf95b | ||
|
|
a9334bc247 | ||
|
|
2357d0c466 | ||
|
|
b003d51276 | ||
|
|
503cbf9830 | ||
|
|
2466058c5a | ||
|
|
6b1f422456 | ||
|
|
1d16d67733 | ||
|
|
6f9d15aed8 | ||
|
|
8725f974da | ||
|
|
2551c949ae | ||
|
|
30c6020ce7 | ||
|
|
d00b1ce1a1 | ||
|
|
2c43d79585 | ||
|
|
3e4aacb2b0 | ||
|
|
67cd22371b | ||
|
|
586941ece7 | ||
|
|
32a57cbfa6 | ||
|
|
1837a69b3e | ||
|
|
aa8bfcfd92 | ||
|
|
9e0c658470 | ||
|
|
66aefff4f3 | ||
|
|
bd0fdeecee | ||
|
|
1055eeb01b | ||
|
|
263a4578d4 | ||
|
|
c446b8a5af | ||
|
|
847b34cdcb | ||
|
|
5a57f90b8f | ||
|
|
f8eb9f5bd0 | ||
|
|
c8c336b574 | ||
|
|
43f1410974 | ||
|
|
1df110b3fb | ||
|
|
9bedce0df5 | ||
|
|
ae1d879e5a | ||
|
|
caab2e0952 | ||
|
|
a29d6517d3 | ||
|
|
dae2781818 | ||
|
|
c1de609b1a | ||
|
|
4e84807950 | ||
|
|
41c9cb45d6 | ||
|
|
2d72772f86 | ||
|
|
1cf1f0e04d | ||
|
|
324b88ec2b | ||
|
|
ec64c7ba0b | ||
|
|
67e0f8570e | ||
|
|
1745100705 | ||
|
|
28501944c5 | ||
|
|
c5c1a68f5c | ||
|
|
e2ed7fbd28 | ||
|
|
ab0675055c | ||
|
|
2b65559f36 | ||
|
|
b8beb07df5 | ||
|
|
01748fec49 | ||
|
|
42a50b1a02 | ||
|
|
d81595f43f | ||
|
|
71fa2d867f | ||
|
|
f55dbb0002 | ||
|
|
3e4d623786 | ||
|
|
1b109aac3a | ||
|
|
8558975d55 | ||
|
|
0e895089c7 | ||
|
|
5dd44f66c1 | ||
|
|
a1cfea46c6 | ||
|
|
42c492c85a | ||
|
|
9e8794a39f | ||
|
|
66c3604b2a | ||
|
|
c0ee1ee27b | ||
|
|
a3e669e433 | ||
|
|
8a83b4fff5 | ||
|
|
69c48d3f5d | ||
|
|
88504a335e | ||
|
|
a44a433807 | ||
|
|
9c03a8ae28 | ||
|
|
767a5f3a94 | ||
|
|
db1e138d36 | ||
|
|
84aa05f9a9 | ||
|
|
1071b85472 | ||
|
|
479412b190 | ||
|
|
ac4fc5b0ba | ||
|
|
4a8770232d | ||
|
|
2ea983bdae | ||
|
|
ffce8fa505 | ||
|
|
cb9e529eb7 | ||
|
|
7f0ee208fa | ||
|
|
2d38652034 | ||
|
|
4a2076a550 | ||
|
|
35049b26fe | ||
|
|
39648ba372 | ||
|
|
44ce0bbffd | ||
|
|
a634472873 | ||
|
|
a98c30f7fa | ||
|
|
43d4b80e11 | ||
|
|
09926fcc53 | ||
|
|
17eef7a4aa | ||
|
|
4738d7c951 | ||
|
|
4be0af5fa3 | ||
|
|
8aaa0900e5 | ||
|
|
49b5d9b886 | ||
|
|
7a3912767b | ||
|
|
d1e473aafe | ||
|
|
c91eb7ed47 | ||
|
|
443f631bac | ||
|
|
95be8d4698 | ||
|
|
f3926d020f | ||
|
|
b48eb5fdd3 | ||
|
|
b0fecdd017 | ||
|
|
793483b6e9 | ||
|
|
c99c7fa9af | ||
|
|
59449a73e1 | ||
|
|
dc86d636ac | ||
|
|
27dd2dd5f3 | ||
|
|
494ae1a47f | ||
|
|
7d1e1e5ff1 | ||
|
|
bcd1567b7d | ||
|
|
ae391b885b | ||
|
|
226bc84a4c | ||
|
|
e60a0c8f61 | ||
|
|
218c90a306 | ||
|
|
2a60c80194 | ||
|
|
35b1c55564 | ||
|
|
20476387ff | ||
|
|
a787748a00 | ||
|
|
34ee540c30 | ||
|
|
975a5ffc82 | ||
|
|
dee0870bf6 | ||
|
|
96ec3bd44e | ||
|
|
e4cf4096a6 | ||
|
|
3d79694c0a | ||
|
|
eab3e4e6f7 | ||
|
|
462152bab2 | ||
|
|
766a455db0 | ||
|
|
30200ac219 | ||
|
|
90a9113971 | ||
|
|
ad1834568f | ||
|
|
6231500b4a | ||
|
|
b2dbc08ea0 | ||
|
|
4700f68f4d | ||
|
|
fa73738309 | ||
|
|
25f92ec438 | ||
|
|
6a59c1dfd6 | ||
|
|
bad6e9d2fe | ||
|
|
e544972c1d | ||
|
|
f1e5de0d58 | ||
|
|
e434e1effb | ||
|
|
ca04b210e6 | ||
|
|
51275af41d | ||
|
|
c2417ac5b3 | ||
|
|
72831d413b | ||
|
|
5cb4bd5819 | ||
|
|
2d9bbca9a9 | ||
|
|
7b54c4e969 | ||
|
|
b50f4ec5ce | ||
|
|
86cc7534c2 | ||
|
|
1ab2565244 | ||
|
|
d2089a9344 | ||
|
|
39153c6936 | ||
|
|
1a8e2b92de | ||
|
|
cf63e751bf | ||
|
|
0c51bc2771 | ||
|
|
5f278cce3e | ||
|
|
f8cf3ac832 | ||
|
|
50bdd02a72 | ||
|
|
424155e5cd | ||
|
|
c4a4d25f7e | ||
|
|
ca2e135cba | ||
|
|
8b4583c59c | ||
|
|
6a836f9151 | ||
|
|
c7b92ad945 | ||
|
|
a05b7a43bd | ||
|
|
929346b2f1 | ||
|
|
23ceed01cb | ||
|
|
2ccf9a1110 | ||
|
|
4917d8e47b | ||
|
|
a0963e5d92 | ||
|
|
e2731b532a | ||
|
|
eccd6056bd | ||
|
|
c1273a4b01 | ||
|
|
017752b06e | ||
|
|
9abb7a04ac | ||
|
|
9533b9d887 | ||
|
|
f1a6feeb8f | ||
|
|
35930f2ffb | ||
|
|
0a1e8a2f8b | ||
|
|
4f9315132b | ||
|
|
196a843148 | ||
|
|
9778875d52 | ||
|
|
fdeb812333 | ||
|
|
e21e12e737 | ||
|
|
52d2322955 | ||
|
|
5ea8f7df33 | ||
|
|
7a9c73df3f | ||
|
|
1f38de989b | ||
|
|
c4f119de9c | ||
|
|
fa2afa856a | ||
|
|
4c83680ae9 | ||
|
|
981665e3e3 | ||
|
|
b3185292b3 | ||
|
|
249f437ff5 | ||
|
|
a7563ab499 | ||
|
|
38f8143fd2 | ||
|
|
a051c17010 | ||
|
|
0b62f8a1c8 | ||
|
|
b803d4f49d | ||
|
|
78e368f406 | ||
|
|
90e613ab26 | ||
|
|
e15914dc2e | ||
|
|
ebe6c39237 | ||
|
|
3369de9660 | ||
|
|
98b831bc22 | ||
|
|
c0f741d914 | ||
|
|
4c27a0cb5c | ||
|
|
4ff5f139f7 | ||
|
|
59910ecadc | ||
|
|
4e37176436 | ||
|
|
35085248b6 | ||
|
|
3ad8a366a6 | ||
|
|
b1660c92cc | ||
|
|
6ec1a3d4cb | ||
|
|
86ffa86800 | ||
|
|
22ad29c92f | ||
|
|
ebc1046ba6 | ||
|
|
43e23b15dc | ||
|
|
c8effe757b | ||
|
|
40b5cd3cff | ||
|
|
26435d85e8 | ||
|
|
b6d5e73708 | ||
|
|
2f193e0c83 | ||
|
|
4897c80646 | ||
|
|
601a455e08 | ||
|
|
d37f4fd77b | ||
|
|
c395cb2206 | ||
|
|
b6f8c612f1 | ||
|
|
18551528ca | ||
|
|
bbc7782f40 | ||
|
|
c121341911 | ||
|
|
990a256e40 | ||
|
|
89e3caf4f2 | ||
|
|
3e4a458fac | ||
|
|
25d2897fb9 | ||
|
|
a2151d0b93 | ||
|
|
5b9dcd829c | ||
|
|
e2e1471dfa | ||
|
|
a664c9abe9 | ||
|
|
0f9b1cdf25 | ||
|
|
7cfd6e7493 | ||
|
|
592f8f0831 | ||
|
|
88c36d2b2d | ||
|
|
dbe5f1dfb2 | ||
|
|
1297ae7bb3 | ||
|
|
ba48a45d39 | ||
|
|
12b5de5cea | ||
|
|
a7b33647ea | ||
|
|
3a7467e6f7 | ||
|
|
8c47ce9b0e | ||
|
|
11f623cc35 | ||
|
|
5365f4b867 | ||
|
|
260a88623e | ||
|
|
2143cab1fa | ||
|
|
5be3662b35 | ||
|
|
c8ab62f9fe | ||
|
|
114c16a36f | ||
|
|
8ac33ceb4c | ||
|
|
9290c20c43 | ||
|
|
c302c26d87 | ||
|
|
f04c6c2032 | ||
|
|
9d35d567ae | ||
|
|
3549ebc5b9 | ||
|
|
68c2dcf67d | ||
|
|
cb4ab20249 | ||
|
|
effafe7b2d | ||
|
|
a2aac1f33c | ||
|
|
7c30f0c236 | ||
|
|
39c71b6f26 | ||
|
|
bc5c1ebb1e | ||
|
|
800470f7fa | ||
|
|
a0195e2e08 | ||
|
|
f60aee8072 | ||
|
|
92b54d18a9 | ||
|
|
aeae6a6ebe | ||
|
|
cf674629cb | ||
|
|
650ba498e1 | ||
|
|
8cbd6b7001 | ||
|
|
096ceb47ea | ||
|
|
d0708ea8fb | ||
|
|
d299e1dbb9 | ||
|
|
ee96a2c625 | ||
|
|
4c8477c4a9 | ||
|
|
aa97c8fd3a | ||
|
|
995eb6b557 | ||
|
|
7f0a33e36a | ||
|
|
2100075972 | ||
|
|
6735401302 | ||
|
|
443e18e84f | ||
|
|
679313e58c | ||
|
|
3b817c20fa | ||
|
|
5baedc39bc | ||
|
|
11177b73a5 | ||
|
|
83263c0b1b | ||
|
|
076d51c6eb | ||
|
|
18e1d962b8 | ||
|
|
989989bda7 | ||
|
|
9e93ac10f4 |
31
.env
31
.env
@@ -1,31 +0,0 @@
|
||||
APP_NAME=Heimdall
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:I206O8ibx+GQyRE7BeOxDobn04Mfmyyc5Ptzns/C0mY=
|
||||
APP_DEBUG=true
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_URL=http://localhost
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
DB_DATABASE=app.sqlite
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
QUEUE_DRIVER=sync
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
28
.env.example
28
.env.example
@@ -1,19 +1,17 @@
|
||||
APP_NAME=Laravel
|
||||
APP_NAME=Heimdall
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_DEBUG=false
|
||||
APP_URL=http://localhost
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
LOG_CHANNEL=daily
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
DB_DATABASE=app.sqlite
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
QUEUE_DRIVER=sync
|
||||
@@ -22,14 +20,24 @@ REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
44
.gitattributes
vendored
44
.gitattributes
vendored
@@ -1,5 +1,49 @@
|
||||
# Configuration file for Git attributes
|
||||
|
||||
# Core Settings {{{
|
||||
# .gitattributes
|
||||
.gitattributes !filter !diff
|
||||
|
||||
# Line Endings
|
||||
* text=auto
|
||||
|
||||
# Set binary to none-text files
|
||||
*.png -text
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
# GitHub Linguist {{{
|
||||
|
||||
# Exclude files/folder from being detected by the GitHub linguist
|
||||
# statistic.
|
||||
node_modules/* linguist-vendored
|
||||
public/* linguist-generated=true
|
||||
vendor/* linguist-vendored
|
||||
|
||||
# Remove Vue as it's currently not used in the project.
|
||||
resources/assets/js/components/ExampleComponent.vue linguist-vendored
|
||||
|
||||
# System Wide
|
||||
*.css linguist-vendored
|
||||
*.scss linguist-vendored
|
||||
*.js linguist-vendored
|
||||
|
||||
# Include user generated files that's removed bu the setting above.
|
||||
resources/assets/js/app.js linguist-vendored=false
|
||||
resources/assets/sass/_app.scss linguist-vendored=false
|
||||
resources/assets/sass/_rune.scss linguist-vendored=false
|
||||
resources/assets/sass/_variables.scss linguist-vendored=false
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
# Archive Exlude {{{
|
||||
# Exclude files/folders from being exported when creating an archive.
|
||||
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.travis.yml export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
|
||||
# }}}
|
||||
|
||||
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/app/SupportedApps
|
||||
/node_modules
|
||||
/public/hot
|
||||
/public/storage
|
||||
@@ -9,4 +10,20 @@ Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
storage/app/public/.DS_Store
|
||||
### macOS ###
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
storage/app/public/avatars/*
|
||||
.env
|
||||
|
||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,5 +1,20 @@
|
||||
# Release Notes
|
||||
|
||||
## v1.4.0 (2018-02-18)
|
||||
|
||||
### Added
|
||||
- Tag(folder) support
|
||||
- Image preview for uploading icons
|
||||
- A load of supported apps, full list of apps https://github.com/linuxserver/Heimdall/projects/1
|
||||
|
||||
### Changed
|
||||
- Edited vendor/laravelcollective/html/src/FormBuilder.php to allow relative links #3369de9
|
||||
- Changed links to use relative links for reverse proxy support
|
||||
- Links open in new tab
|
||||
|
||||
### Fixed
|
||||
- adds all the fixes in the 1.3.x point releases and on master
|
||||
|
||||
## v1.3.0 (2018-02-09)
|
||||
|
||||
### Added
|
||||
|
||||
14
SECURITY.md
Normal file
14
SECURITY.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2.3.x | :white_check_mark: |
|
||||
| < 2.3 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
You can report any vulnerabilities on our discord server by DM-ing a team member, or asking a team member to DM you.
|
||||
|
||||
https://discord.com/invite/YWrKVTn
|
||||
127
app/Application.php
Normal file
127
app/Application.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Application extends Model
|
||||
{
|
||||
public $incrementing = false;
|
||||
|
||||
protected $primaryKey = 'appid';
|
||||
|
||||
//
|
||||
public function icon()
|
||||
{
|
||||
if(!file_exists(storage_path('app/public/'.$this->icon))) {
|
||||
$img_src = app_path('SupportedApps/'.$this->name.'/'.str_replace('icons/', '', $this->icon));
|
||||
$img_dest = storage_path('app/public/'.$this->icon);
|
||||
//die("i: ".$img_src);
|
||||
@copy($img_src, $img_dest);
|
||||
}
|
||||
|
||||
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
public function iconView()
|
||||
{
|
||||
return asset('storage/'.$this->icon);
|
||||
}
|
||||
|
||||
public function defaultColour()
|
||||
{
|
||||
// check if light or dark
|
||||
if($this->tile_background == 'light') return '#fafbfc';
|
||||
return '#161b1f';
|
||||
}
|
||||
|
||||
public function class()
|
||||
{
|
||||
$name = $this->name;
|
||||
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
|
||||
|
||||
$class = '\App\SupportedApps\\'.$name.'\\'.$name;
|
||||
return $class;
|
||||
}
|
||||
|
||||
public static function classFromName($name)
|
||||
{
|
||||
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
|
||||
|
||||
$class = '\App\SupportedApps\\'.$name.'\\'.$name;
|
||||
return $class;
|
||||
}
|
||||
|
||||
|
||||
public static function apps()
|
||||
{
|
||||
$json = json_decode(file_get_contents(storage_path('app/supportedapps.json'))) ?? [];
|
||||
$apps = collect($json->apps);
|
||||
$sorted = $apps->sortBy('name', SORT_NATURAL|SORT_FLAG_CASE);
|
||||
return $sorted;
|
||||
}
|
||||
|
||||
public static function autocomplete()
|
||||
{
|
||||
$apps = self::apps();
|
||||
$list = [];
|
||||
foreach($apps as $app) {
|
||||
$list[] = (object)[
|
||||
'label' => $app->name,
|
||||
'value' => $app->appid
|
||||
];
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function getApp($appid)
|
||||
{
|
||||
$localapp = Application::where('appid', $appid)->first();
|
||||
$app = self::single($appid);
|
||||
|
||||
$application = ($localapp) ? $localapp : new Application;
|
||||
|
||||
if(!file_exists(app_path('SupportedApps/'.className($app->name)))) {
|
||||
SupportedApps::getFiles($app);
|
||||
SupportedApps::saveApp($app, $application);
|
||||
} else {
|
||||
// check if there has been an update for this app
|
||||
if($localapp) {
|
||||
if($localapp->sha !== $app->sha) {
|
||||
SupportedApps::getFiles($app);
|
||||
$app = SupportedApps::saveApp($app, $application);
|
||||
}
|
||||
} else {
|
||||
SupportedApps::getFiles($app);
|
||||
$app = SupportedApps::saveApp($app, $application);
|
||||
|
||||
}
|
||||
}
|
||||
return $app;
|
||||
|
||||
}
|
||||
|
||||
public static function single($appid)
|
||||
{
|
||||
$apps = self::apps();
|
||||
$app = $apps->where('appid', $appid)->first();
|
||||
if ($app === null) return null;
|
||||
$classname = preg_replace('/[^\p{L}\p{N}]/u', '', $app->name);
|
||||
$app->class = '\App\SupportedApps\\'.$classname.'\\'.$classname;
|
||||
return $app;
|
||||
}
|
||||
|
||||
public static function applist()
|
||||
{
|
||||
$list = [];
|
||||
$list['null'] = 'None';
|
||||
$apps = self::apps();
|
||||
foreach($apps as $app) {
|
||||
$list[$app->appid] = $app->name;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
79
app/Console/Commands/RegisterApp.php
Normal file
79
app/Console/Commands/RegisterApp.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Application;
|
||||
use App\SupportedApps;
|
||||
|
||||
class RegisterApp extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'register:app {folder}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add a local app to the registry';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$folder = $this->argument('folder');
|
||||
if($folder == 'all') {
|
||||
$apps = scandir(app_path('SupportedApps'));
|
||||
foreach($apps as $folder) {
|
||||
if($folder == '.' || $folder == '..') continue;
|
||||
$this->addApp($folder);
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->addApp($folder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function addApp($folder)
|
||||
{
|
||||
$json = app_path('SupportedApps/'.$folder.'/app.json');
|
||||
if(file_exists($json)) {
|
||||
$app = json_decode(file_get_contents($json));
|
||||
if(isset($app->appid)) {
|
||||
$exists = Application::find($app->appid);
|
||||
if($exists) {
|
||||
$this->error('Application already registered - '.$exists->name." - ".$exists->appid);
|
||||
} else {
|
||||
// Doesn't exist so add it
|
||||
SupportedApps::saveApp($app, new Application);
|
||||
$this->info("Application Added - ".$app->name." - ".$app->appid);
|
||||
}
|
||||
} else {
|
||||
$this->error('No App ID for - '.$folder);
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->error('Could not find '.$json);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
12
app/EnhancedApps.php
Normal file
12
app/EnhancedApps.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace App;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
interface EnhancedApps
|
||||
{
|
||||
public function test();
|
||||
public function livestats();
|
||||
public function url($endpoint);
|
||||
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
@@ -22,32 +22,20 @@ class Handler extends ExceptionHandler
|
||||
* @var array
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
|
||||
/**
|
||||
* Report or log an exception.
|
||||
* Register the exception handling callbacks for the application.
|
||||
*
|
||||
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Exception $exception)
|
||||
public function register()
|
||||
{
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Exception $exception
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function render($request, Exception $exception)
|
||||
{
|
||||
return parent::render($request, $exception);
|
||||
$this->reportable(function (Throwable $e) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
function format_bytes($bytes, $is_drive_size = true, $beforeunit = '', $afterunit = '')
|
||||
{
|
||||
$btype = ($is_drive_size === true) ? 1000 : 1024;
|
||||
@@ -10,3 +12,68 @@ function format_bytes($bytes, $is_drive_size = true, $beforeunit = '', $afteruni
|
||||
elseif($labels[$x] == "MB") return(round($bytes, 2).$beforeunit.$labels[$x].$afterunit);
|
||||
else return(round($bytes, 0).$beforeunit.$labels[$x].$afterunit);
|
||||
}
|
||||
|
||||
function str_slug($title, $separator = '-', $language = 'en')
|
||||
{
|
||||
return Str::slug($title, $separator, $language);
|
||||
}
|
||||
|
||||
if (! function_exists('str_is')) {
|
||||
/**
|
||||
* Determine if a given string matches a given pattern.
|
||||
*
|
||||
* @param string|array $pattern
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated Str::is() should be used directly instead. Will be removed in Laravel 6.0.
|
||||
*/
|
||||
function str_is($pattern, $value)
|
||||
{
|
||||
return Str::is($pattern, $value);
|
||||
}
|
||||
}
|
||||
|
||||
function get_brightness($hex) {
|
||||
// returns brightness value from 0 to 255
|
||||
// strip off any leading #
|
||||
$hex = str_replace('#', '', $hex);
|
||||
if(strlen($hex) == 3) {
|
||||
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
|
||||
}
|
||||
|
||||
$c_r = hexdec(substr($hex, 0, 2));
|
||||
$c_g = hexdec(substr($hex, 2, 2));
|
||||
$c_b = hexdec(substr($hex, 4, 2));
|
||||
|
||||
return (($c_r * 299) + ($c_g * 587) + ($c_b * 114)) / 1000;
|
||||
}
|
||||
|
||||
function title_color($hex)
|
||||
{
|
||||
if(get_brightness($hex) > 130) {
|
||||
return ' black';
|
||||
} else {
|
||||
return ' white';
|
||||
}
|
||||
}
|
||||
|
||||
function getLinkTargetAttribute()
|
||||
{
|
||||
$target = \App\Setting::fetch('window_target');
|
||||
|
||||
if($target === 'current') {
|
||||
return '';
|
||||
} else {
|
||||
return ' target="' . $target . '"';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function className($name)
|
||||
{
|
||||
$name = preg_replace('/[^\p{L}\p{N}]/u', '', $name);
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use App\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
@@ -25,7 +30,7 @@ class LoginController extends Controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
protected $redirectTo = '/';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
@@ -34,6 +39,88 @@ class LoginController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
Session::put('backUrl', URL::previous());
|
||||
$this->middleware('guest')->except('logout');
|
||||
}
|
||||
|
||||
public function username()
|
||||
{
|
||||
return 'username';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a login request to the application.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
$current_user = User::currentUser();
|
||||
$request->merge(['username' => $current_user->username, 'remember' => true]);
|
||||
//die(print_r($request->all()));
|
||||
$this->validateLogin($request);
|
||||
|
||||
// If the class is using the ThrottlesLogins trait, we can automatically throttle
|
||||
// the login attempts for this application. We'll key this by the username and
|
||||
// the IP address of the client making these requests into this application.
|
||||
if ($this->hasTooManyLoginAttempts($request)) {
|
||||
$this->fireLockoutEvent($request);
|
||||
|
||||
return $this->sendLockoutResponse($request);
|
||||
}
|
||||
|
||||
if ($this->attemptLogin($request)) {
|
||||
return $this->sendLoginResponse($request);
|
||||
}
|
||||
|
||||
// If the login attempt was unsuccessful we will increment the number of attempts
|
||||
// to login and redirect the user back to the login form. Of course, when this
|
||||
// user surpasses their maximum number of attempts they will get locked out.
|
||||
$this->incrementLoginAttempts($request);
|
||||
|
||||
return $this->sendFailedLoginResponse($request);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
}
|
||||
|
||||
public function setUser(User $user)
|
||||
{
|
||||
Auth::logout();
|
||||
session(['current_user' => $user]);
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
|
||||
public function autologin($uuid)
|
||||
{
|
||||
$user = User::where('autologin', $uuid)->first();
|
||||
Auth::login($user, true);
|
||||
session(['current_user' => $user]);
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application's login form.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function showLoginForm()
|
||||
{
|
||||
return view('auth.login');
|
||||
}
|
||||
|
||||
protected function authenticated(Request $request, $user)
|
||||
{
|
||||
return back();
|
||||
}
|
||||
|
||||
public function redirectTo()
|
||||
{
|
||||
return Session::get('url.intended') ? Session::get('url.intended') : $this->redirectTo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class RegisterController extends Controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
protected $redirectTo = '/';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
|
||||
@@ -25,7 +25,7 @@ class ResetPasswordController extends Controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
protected $redirectTo = '/';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
|
||||
@@ -6,8 +6,27 @@ use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\User;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
|
||||
protected $user;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->user = $this->user();
|
||||
//print_r($this->user);
|
||||
return $next($request);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return User::currentUser();
|
||||
}
|
||||
}
|
||||
|
||||
28
app/Http/Controllers/HomeController.php
Normal file
28
app/Http/Controllers/HomeController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application dashboard.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,30 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Artisan;
|
||||
use App\Application;
|
||||
use App\Item;
|
||||
use App\Setting;
|
||||
use App\SupportedApps\Nzbget;
|
||||
use App\User;
|
||||
use GrahamCampbell\GitHub\Facades\GitHub;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\SupportedApps;
|
||||
use App\Jobs\ProcessApps;
|
||||
use App\Search;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
|
||||
class ItemController extends Controller
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource on the dashboard.
|
||||
*
|
||||
@@ -18,8 +33,16 @@ class ItemController extends Controller
|
||||
*/
|
||||
public function dash()
|
||||
{
|
||||
$data['apps'] = Item::pinned()->orderBy('order', 'asc')->get();
|
||||
$data['all_apps'] = Item::all();
|
||||
$data['apps'] = Item::whereHas('parents', function ($query) {
|
||||
$query->where('id', 0);
|
||||
})->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
|
||||
|
||||
$data['all_apps'] = Item::whereHas('parents', function ($query) {
|
||||
$query->where('id', 0);
|
||||
})->orWhere('type', 1)->orderBy('order', 'asc')->get();
|
||||
|
||||
//$data['all_apps'] = Item::doesntHave('parents')->get();
|
||||
//die(print_r($data['apps']));
|
||||
return view('welcome', $data);
|
||||
}
|
||||
|
||||
@@ -37,9 +60,8 @@ class ItemController extends Controller
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Pin item on the dashboard.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
@@ -49,7 +71,8 @@ class ItemController extends Controller
|
||||
$item = Item::findOrFail($id);
|
||||
$item->pinned = true;
|
||||
$item->save();
|
||||
return redirect()->route('dash');
|
||||
$route = route('dash', []);
|
||||
return redirect($route);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +85,8 @@ class ItemController extends Controller
|
||||
$item = Item::findOrFail($id);
|
||||
$item->pinned = false;
|
||||
$item->save();
|
||||
return redirect()->route('dash');
|
||||
$route = route('dash', []);
|
||||
return redirect($route);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,18 +94,24 @@ class ItemController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function pinToggle($id, $ajax=false)
|
||||
public function pinToggle($id, $ajax=false, $tag=false)
|
||||
{
|
||||
$item = Item::findOrFail($id);
|
||||
$new = ((bool)$item->pinned === true) ? false : true;
|
||||
$item->pinned = $new;
|
||||
$item->save();
|
||||
if($ajax) {
|
||||
$data['apps'] = Item::pinned()->get();
|
||||
if(is_numeric($tag) && $tag > 0) {
|
||||
$item = Item::whereId($tag)->first();
|
||||
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
|
||||
} else {
|
||||
$data['apps'] = Item::pinned()->orderBy('order', 'asc')->get();
|
||||
}
|
||||
$data['ajax'] = true;
|
||||
return view('sortable', $data);
|
||||
} else {
|
||||
return redirect()->route('dash');
|
||||
$route = route('dash', []);
|
||||
return redirect($route);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,8 +125,8 @@ class ItemController extends Controller
|
||||
{
|
||||
$trash = (bool)$request->input('trash');
|
||||
|
||||
$data['apps'] = Item::orderBy('title', 'asc')->get();
|
||||
$data['trash'] = Item::onlyTrashed()->get();
|
||||
$data['apps'] = Item::ofType('item')->orderBy('title', 'asc')->get();
|
||||
$data['trash'] = Item::ofType('item')->onlyTrashed()->get();
|
||||
if($trash) {
|
||||
return view('items.trash', $data);
|
||||
} else {
|
||||
@@ -113,11 +143,75 @@ class ItemController extends Controller
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
$data = [];
|
||||
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
|
||||
$data['tags']->prepend(__('app.dashboard'), 0);
|
||||
$data['current_tags'] = collect([0 => __('app.dashboard')]);
|
||||
return view('items.create', $data);
|
||||
|
||||
}
|
||||
|
||||
public function storelogic($request, $id = null)
|
||||
{
|
||||
$application = Application::single($request->input('appid'));
|
||||
$validatedData = $request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'url' => 'required',
|
||||
]);
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
]);
|
||||
} elseif(strpos($request->input('icon'), 'http') === 0) {
|
||||
$contents = file_get_contents($request->input('icon'));
|
||||
|
||||
if ($application) {
|
||||
$icon = $application->icon;
|
||||
} else {
|
||||
$file = $request->input('icon');
|
||||
$path_parts = pathinfo($file);
|
||||
$icon = md5($contents);
|
||||
$icon .= '.'.$path_parts['extension'];
|
||||
}
|
||||
$path = 'icons/'.$icon;
|
||||
Storage::disk('public')->put($path, $contents);
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
]);
|
||||
}
|
||||
|
||||
$config = Item::checkConfig($request->input('config'));
|
||||
$current_user = User::currentUser();
|
||||
$request->merge([
|
||||
'description' => $config,
|
||||
'user_id' => $current_user->id
|
||||
]);
|
||||
|
||||
if($request->input('appid') === 'null') {
|
||||
$request->merge([
|
||||
'class' => null,
|
||||
]);
|
||||
} else {
|
||||
$request->merge([
|
||||
'class' => Application::classFromName($application->name),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if($id === null) {
|
||||
$item = Item::create($request->all());
|
||||
} else {
|
||||
$item = Item::find($id);
|
||||
$item->update($request->all());
|
||||
}
|
||||
|
||||
|
||||
$item->parents()->sync($request->tags);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
@@ -126,29 +220,10 @@ class ItemController extends Controller
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
$validatedData = $request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'url' => 'required',
|
||||
]);
|
||||
$this->storelogic($request);
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
]);
|
||||
}
|
||||
|
||||
$config = Item::checkConfig($request->input('config'));
|
||||
$request->merge([
|
||||
'description' => $config
|
||||
]);
|
||||
|
||||
//die(print_r($request->input('config')));
|
||||
|
||||
Item::create($request->all());
|
||||
|
||||
return redirect()->route('dash')
|
||||
$route = route('dash', []);
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.item_created'));
|
||||
}
|
||||
|
||||
@@ -173,10 +248,20 @@ class ItemController extends Controller
|
||||
{
|
||||
// Get the item
|
||||
$item = Item::find($id);
|
||||
|
||||
if($item->appid === null && $item->class !== null) { // old apps wont have an app id so set it
|
||||
$app = Application::where('class', $item->class)->first();
|
||||
if($app) {
|
||||
$item->appid = $app->appid;
|
||||
}
|
||||
}
|
||||
$data['item'] = $item;
|
||||
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
|
||||
$data['tags']->prepend(__('app.dashboard'), 0);
|
||||
$data['current_tags'] = $data['item']->tags();
|
||||
//$data['current_tags'] = $data['item']->parent;
|
||||
//die(print_r($data['current_tags']));
|
||||
// show the edit form and pass the nerd
|
||||
return view('items.edit')
|
||||
->with('item', $item);
|
||||
return view('items.edit', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,26 +273,9 @@ class ItemController extends Controller
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'url' => 'required',
|
||||
]);
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
]);
|
||||
}
|
||||
|
||||
$config = Item::checkConfig($request->input('config'));
|
||||
$request->merge([
|
||||
'description' => $config
|
||||
]);
|
||||
|
||||
Item::find($id)->update($request->all());
|
||||
|
||||
return redirect()->route('dash')
|
||||
$this->storelogic($request, $id);
|
||||
$route = route('dash', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_updated'));
|
||||
}
|
||||
|
||||
@@ -228,8 +296,9 @@ class ItemController extends Controller
|
||||
} else {
|
||||
Item::find($id)->delete();
|
||||
}
|
||||
|
||||
return redirect()->route('items.index')
|
||||
|
||||
$route = route('items.index', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_deleted'));
|
||||
}
|
||||
|
||||
@@ -244,21 +313,13 @@ class ItemController extends Controller
|
||||
//
|
||||
Item::withTrashed()
|
||||
->where('id', $id)
|
||||
->restore();
|
||||
return redirect()->route('items.index')
|
||||
->restore();
|
||||
|
||||
$route = route('items.index', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_restored'));
|
||||
}
|
||||
|
||||
public function isSupportedAppByKey($app)
|
||||
{
|
||||
$output = false;
|
||||
$all_supported = Item::supportedList();
|
||||
if(array_key_exists($app, $all_supported)) {
|
||||
$output = new $all_supported[$app];
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return details for supported apps
|
||||
*
|
||||
@@ -267,21 +328,49 @@ class ItemController extends Controller
|
||||
public function appload(Request $request)
|
||||
{
|
||||
$output = [];
|
||||
$app = $request->input('app');
|
||||
$appid = $request->input('app');
|
||||
|
||||
if(($app_details = $this->isSupportedAppByKey($app)) !== false) {
|
||||
// basic details
|
||||
$output['icon'] = $app_details->icon();
|
||||
$output['colour'] = $app_details->defaultColour();
|
||||
if($appid === "null") return null;
|
||||
/*$appname = $request->input('app');
|
||||
//die($appname);
|
||||
|
||||
// live details
|
||||
if($app_details instanceof \App\SupportedApps\Contracts\Livestats) {
|
||||
$output['config'] = $app_details->configDetails();
|
||||
} else {
|
||||
$output['config'] = null;
|
||||
}
|
||||
$app_details = Application::where('name', $appname)->firstOrFail();
|
||||
$appclass = $app_details->class();
|
||||
$app = new $appclass;
|
||||
|
||||
// basic details
|
||||
$output['icon'] = $app_details->icon();
|
||||
$output['name'] = $app_details->name;
|
||||
$output['iconview'] = $app_details->iconView();
|
||||
$output['colour'] = $app_details->defaultColour();
|
||||
$output['class'] = $appclass;
|
||||
|
||||
// live details
|
||||
if($app instanceof \App\EnhancedApps) {
|
||||
$output['config'] = className($app_details->name).'.config';
|
||||
} else {
|
||||
$output['config'] = null;
|
||||
}*/
|
||||
|
||||
$output['config'] = null;
|
||||
$output['custom'] = null;
|
||||
|
||||
$app = Application::single($appid);
|
||||
$output = (array)$app;
|
||||
|
||||
if((boolean)$app->enhanced === true) {
|
||||
// if(!isset($app->config)) { // class based config
|
||||
$appdetails = Application::getApp($appid);
|
||||
$output['custom'] = className($appdetails->name).'.config';
|
||||
// }
|
||||
}
|
||||
|
||||
$output['colour'] = ($app->tile_background == 'light') ? '#fafbfc' : '#161b1f';
|
||||
$output['iconview'] = config('app.appsource').'icons/' . $app->icon;
|
||||
|
||||
;
|
||||
|
||||
|
||||
return json_encode($output);
|
||||
}
|
||||
|
||||
@@ -294,25 +383,69 @@ class ItemController extends Controller
|
||||
|
||||
$app_details = new $app();
|
||||
$app_details->config = (object)$data;
|
||||
$app_details->testConfig();
|
||||
$app_details->test();
|
||||
}
|
||||
|
||||
public function execute($url, $attrs = [], $overridevars=false)
|
||||
{
|
||||
$res = null;
|
||||
|
||||
$vars = ($overridevars !== false) ?
|
||||
$overridevars : [
|
||||
'http_errors' => false,
|
||||
'timeout' => 15,
|
||||
'connect_timeout' => 15,
|
||||
'verify' => false
|
||||
];
|
||||
|
||||
$client = new Client($vars);
|
||||
|
||||
$method = 'GET';
|
||||
|
||||
try {
|
||||
return $client->request($method, $url, $attrs);
|
||||
} catch (\GuzzleHttp\Exception\ConnectException $e) {
|
||||
Log::error("Connection refused");
|
||||
Log::debug($e->getMessage());
|
||||
} catch (\GuzzleHttp\Exception\ServerException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
public function websitelookup($url)
|
||||
{
|
||||
$url = \base64_decode($url);
|
||||
$data = $this->execute($url);
|
||||
return $data->getBody();
|
||||
}
|
||||
|
||||
public function getStats($id)
|
||||
{
|
||||
$item = Item::find($id);
|
||||
|
||||
$config = json_decode($item->description);
|
||||
if(isset($config->type)) {
|
||||
$config->url = $item->url;
|
||||
if(isset($config->override_url) && !empty($config->override_url)) {
|
||||
$config->url = $config->override_url;
|
||||
}
|
||||
$app_details = new $config->type;
|
||||
$app_details->config = $config;
|
||||
echo $app_details->executeConfig();
|
||||
$config = $item->getconfig();
|
||||
if(isset($item->class)) {
|
||||
$application = new $item->class;
|
||||
$application->config = $config;
|
||||
echo $application->livestats();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function checkAppList()
|
||||
{
|
||||
ProcessApps::dispatch();
|
||||
$route = route('items.index');
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.updating'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
28
app/Http/Controllers/SearchController.php
Normal file
28
app/Http/Controllers/SearchController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Search;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$requestprovider = $request->input('provider');
|
||||
$query = $request->input('q');
|
||||
|
||||
$provider = Search::providerDetails($requestprovider);
|
||||
|
||||
if($provider->type == 'standard') {
|
||||
return redirect($provider->url.'?'.$provider->query.'='.urlencode($query));
|
||||
} elseif($provider->type == 'external') {
|
||||
$class = new $provider->class;
|
||||
//print_r($provider);
|
||||
return $class->getResults($query, $provider);
|
||||
}
|
||||
|
||||
//print_r($provider);
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,17 @@ namespace App\Http\Controllers;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Setting;
|
||||
use App\SettingGroup;
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
@@ -31,6 +38,7 @@ class SettingsController extends Controller
|
||||
public function edit($id)
|
||||
{
|
||||
$setting = Setting::find($id);
|
||||
//die("s: ".$setting->label);
|
||||
|
||||
if((bool)$setting->system === true) return abort(404);
|
||||
|
||||
@@ -39,7 +47,9 @@ class SettingsController extends Controller
|
||||
'setting' => $setting,
|
||||
]);
|
||||
} else {
|
||||
return redirect()->route('settings.list')->with([
|
||||
$route = route('settings.list', []);
|
||||
return redirect($route)
|
||||
->with([
|
||||
'error' => __('app.alert.error.not_exist'),
|
||||
]);
|
||||
}
|
||||
@@ -53,31 +63,37 @@ class SettingsController extends Controller
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$setting = Setting::find($id);
|
||||
$user = $this->user();
|
||||
|
||||
if (!is_null($setting)) {
|
||||
$data = Setting::getInput();
|
||||
$data = Setting::getInput($request);
|
||||
|
||||
$setting_value = null;
|
||||
|
||||
if ($setting->type == 'image') {
|
||||
|
||||
|
||||
if($request->hasFile('value')) {
|
||||
$path = $request->file('value')->store('backgrounds');
|
||||
$setting->value = $path;
|
||||
$setting_value = $path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
$setting->value = $data->value;
|
||||
$setting_value = $data->value;
|
||||
}
|
||||
|
||||
$setting->save();
|
||||
|
||||
return redirect()->route('settings.index')->with([
|
||||
$user->settings()->detach($setting->id);
|
||||
$user->settings()->save($setting, ['uservalue' => $setting_value]);
|
||||
|
||||
$route = route('settings.index', []);
|
||||
return redirect($route)
|
||||
->with([
|
||||
'success' => __('app.alert.success.setting_updated'),
|
||||
]);
|
||||
} else {
|
||||
return redirect()->route('settings.index')->with([
|
||||
$route = route('settings.index', []);
|
||||
return redirect($route)
|
||||
->with([
|
||||
'error' => __('app.alert.error.not_exist'),
|
||||
]);
|
||||
}
|
||||
@@ -89,14 +105,23 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function clear($id)
|
||||
{
|
||||
$user = $this->user();
|
||||
$setting = Setting::find($id);
|
||||
if((bool)$setting->system !== true) {
|
||||
$setting->value = '';
|
||||
$setting->save();
|
||||
$user->settings()->detach($setting->id);
|
||||
$user->settings()->save($setting, ['uservalue' => '']);
|
||||
}
|
||||
return redirect()->route('settings.index')->with([
|
||||
$route = route('settings.index', []);
|
||||
return redirect($route)
|
||||
->with([
|
||||
'success' => __('app.alert.success.setting_updated'),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function search(Request $request)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
202
app/Http/Controllers/TagController.php
Normal file
202
app/Http/Controllers/TagController.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Item;
|
||||
use App\User;
|
||||
use DB;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$trash = (bool)$request->input('trash');
|
||||
|
||||
$data['apps'] = Item::ofType('tag')->where('id', '>', 0)->orderBy('title', 'asc')->get();
|
||||
$data['trash'] = Item::ofType('tag')->where('id', '>', 0)->onlyTrashed()->get();
|
||||
if($trash) {
|
||||
return view('tags.trash', $data);
|
||||
} else {
|
||||
return view('tags.list', $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data = [];
|
||||
return view('tags.create', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'title' => 'required|max:255',
|
||||
]);
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
]);
|
||||
}
|
||||
|
||||
$slug = str_slug($request->title, '-');
|
||||
|
||||
$current_user = User::currentUser();
|
||||
|
||||
// set item type to tag
|
||||
$request->merge([
|
||||
'type' => '1',
|
||||
'url' => $slug,
|
||||
'user_id' => $current_user->id
|
||||
]);
|
||||
//die(print_r($request->all()));
|
||||
Item::create($request->all());
|
||||
|
||||
$route = route('dash', []);
|
||||
return redirect($route)
|
||||
->with('success', __('app.alert.success.tag_created'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($slug)
|
||||
{
|
||||
$item = Item::whereUrl($slug)->first();
|
||||
//print_r($item);
|
||||
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
|
||||
$data['tag'] = $item->id;
|
||||
$data['all_apps'] = $item->children;
|
||||
return view('welcome', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
// Get the item
|
||||
$item = Item::find($id);
|
||||
|
||||
// show the edit form and pass the nerd
|
||||
return view('tags.edit')
|
||||
->with('item', $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'title' => 'required|max:255',
|
||||
]);
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('icons');
|
||||
$request->merge([
|
||||
'icon' => $path
|
||||
]);
|
||||
}
|
||||
|
||||
$slug = str_slug($request->title, '-');
|
||||
// set item type to tag
|
||||
$request->merge([
|
||||
'url' => $slug
|
||||
]);
|
||||
|
||||
Item::find($id)->update($request->all());
|
||||
|
||||
$route = route('dash', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.tag_updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request, $id)
|
||||
{
|
||||
//
|
||||
$force = (bool)$request->input('force');
|
||||
if($force) {
|
||||
Item::withTrashed()
|
||||
->where('id', $id)
|
||||
->forceDelete();
|
||||
} else {
|
||||
Item::find($id)->delete();
|
||||
}
|
||||
|
||||
$route = route('tags.index', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_deleted'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the specified resource from soft deletion.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function restore($id)
|
||||
{
|
||||
//
|
||||
Item::withTrashed()
|
||||
->where('id', $id)
|
||||
->restore();
|
||||
$route = route('tags.index', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.item_restored'));
|
||||
}
|
||||
|
||||
public function add($tag, $item)
|
||||
{
|
||||
$output = 0;
|
||||
$tag = Item::find($tag);
|
||||
$item = Item::find($item);
|
||||
if($tag && $item) {
|
||||
// only add items, not cats
|
||||
if((int)$item->type === 0) {
|
||||
$tag->children()->attach($item);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
175
app/Http/Controllers/UserController.php
Normal file
175
app/Http/Controllers/UserController.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('allowed')->except(['selectUser']);
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data['users'] = User::all();
|
||||
return view('users.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data = [];
|
||||
return view('users.create', $data);
|
||||
}
|
||||
|
||||
public function selectUser()
|
||||
{
|
||||
Auth::logout();
|
||||
$data['users'] = User::all();
|
||||
return view('userselect', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'username' => 'required|max:255|unique:users',
|
||||
'email' => 'required|email',
|
||||
'password' => 'nullable|confirmed',
|
||||
'password_confirmation' => 'nullable'
|
||||
|
||||
]);
|
||||
$user = new User;
|
||||
$user->username = $request->input('username');
|
||||
$user->email = $request->input('email');
|
||||
$user->public_front = $request->input('public_front');
|
||||
|
||||
$password = $request->input('password');
|
||||
if(!empty($password)) {
|
||||
$user->password = bcrypt($password);
|
||||
}
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('avatars');
|
||||
$user->avatar = $path;
|
||||
}
|
||||
|
||||
if ((bool)$request->input('autologin_allow') === true) {
|
||||
$user->autologin = (string)Str::uuid();
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
$route = route('dash', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(User $user)
|
||||
{
|
||||
$data['user'] = $user;
|
||||
return view('users.edit', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, User $user)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'username' => 'required|max:255|unique:users,username,'.$user->id,
|
||||
'email' => 'required|email',
|
||||
'password' => 'nullable|confirmed',
|
||||
'password_confirmation' => 'nullable'
|
||||
]);
|
||||
//die(print_r($request->all()));
|
||||
|
||||
$user->username = $request->input('username');
|
||||
$user->email = $request->input('email');
|
||||
$user->public_front = $request->input('public_front');
|
||||
|
||||
$password = $request->input('password');
|
||||
if(!empty($password)) {
|
||||
$user->password = bcrypt($password);
|
||||
} elseif($password == 'null') {
|
||||
$user->password = null;
|
||||
}
|
||||
|
||||
if($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('avatars');
|
||||
$user->avatar = $path;
|
||||
}
|
||||
|
||||
if ((bool)$request->input('autologin_allow') === true) {
|
||||
$user->autologin = (is_null($user->autologin)) ? (string)Str::uuid() : $user->autologin;
|
||||
} else {
|
||||
$user->autologin = null;
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
$route = route('dash', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_updated'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(User $user)
|
||||
{
|
||||
if($user->id !== 1) {
|
||||
$user->delete();
|
||||
$route = route('dash', []);
|
||||
return redirect($route)
|
||||
->with('success',__('app.alert.success.user_deleted'));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ class Kernel extends HttpKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $routeMiddleware = [
|
||||
'allowed' => \App\Http\Middleware\CheckAllowed::class,
|
||||
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
|
||||
48
app/Http/Middleware/CheckAllowed.php
Normal file
48
app/Http/Middleware/CheckAllowed.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Session;
|
||||
|
||||
class CheckAllowed
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$route = Route::currentRouteName();
|
||||
$current_user = User::currentUser();
|
||||
|
||||
if(str_is('users*', $route)) {
|
||||
if($current_user->id !== 1) {
|
||||
return redirect()->route('dash');
|
||||
}
|
||||
}
|
||||
|
||||
if($route == 'dash') {
|
||||
//print_r(User::all());
|
||||
//die("here".var_dump($current_user->password));
|
||||
if((bool)$current_user->public_front === true) return $next($request);
|
||||
}
|
||||
|
||||
if(empty($current_user->password)) return $next($request);
|
||||
|
||||
// Check if user is logged in as $current_user
|
||||
if (Auth::check()) {
|
||||
$loggedin_user = Auth::user();
|
||||
if($loggedin_user->id === $current_user->id) return $next($request);
|
||||
}
|
||||
|
||||
return Auth::authenticate();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class RedirectIfAuthenticated
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
{
|
||||
if (Auth::guard($guard)->check()) {
|
||||
return redirect('/home');
|
||||
return redirect()->intended();
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
||||
@@ -12,18 +12,12 @@ class TrustProxies extends Middleware
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $proxies;
|
||||
protected $proxies = ['192.168.0.0/16', '172.16.0.0/12','10.0.0.0/8', '127.0.0.1'];
|
||||
|
||||
/**
|
||||
* The current proxy header mappings.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $headers = [
|
||||
Request::HEADER_FORWARDED => 'FORWARDED',
|
||||
Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
|
||||
Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
|
||||
Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
|
||||
Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
|
||||
];
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
class VerifyCsrfToken extends Middleware
|
||||
{
|
||||
@@ -18,4 +19,40 @@ class VerifyCsrfToken extends Middleware
|
||||
'test_config',
|
||||
//'get_stats'
|
||||
];
|
||||
|
||||
/**
|
||||
* Add the CSRF token to the response cookies.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Symfony\Component\HttpFoundation\Response $response
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
protected function addCookieToResponse($request, $response)
|
||||
{
|
||||
$config = config('session');
|
||||
|
||||
if ($response instanceof Responsable) {
|
||||
$response = $response->toResponse($request);
|
||||
}
|
||||
|
||||
$response->headers->setCookie(
|
||||
new Cookie(
|
||||
'HEIMDALL-XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
|
||||
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the cookie contents should be serialized.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function serialized()
|
||||
{
|
||||
return EncryptCookies::serialized('HEIMDALL-XSRF-TOKEN');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
265
app/Item.php
265
app/Item.php
@@ -5,15 +5,32 @@ namespace App;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Symfony\Component\ClassLoader\ClassMapGenerator;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\User;
|
||||
use App\ItemTag;
|
||||
use App\Application;
|
||||
|
||||
class Item extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::addGlobalScope('user_id', function (Builder $builder) {
|
||||
$current_user = User::currentUser();
|
||||
if($current_user) {
|
||||
$builder->where('user_id', $current_user->id)->orWhere('user_id', 0);
|
||||
} else {
|
||||
$builder->where('user_id', 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
protected $fillable = [
|
||||
'title', 'url', 'colour', 'icon', 'description', 'pinned', 'order'
|
||||
'title', 'url', 'colour', 'icon', 'appdescription', 'description', 'pinned', 'order', 'type', 'class', 'user_id', 'appid'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -23,25 +40,6 @@ class Item extends Model
|
||||
*/
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
public static function supportedList()
|
||||
{
|
||||
return [
|
||||
'Duplicati' => \App\SupportedApps\Duplicati::class,
|
||||
'Emby' => \App\SupportedApps\Emby::class,
|
||||
'NZBGet' => \App\SupportedApps\Nzbget::class,
|
||||
'pFsense' => \App\SupportedApps\Pfsense::class,
|
||||
'Pihole' => \App\SupportedApps\Pihole::class,
|
||||
'Plex' => \App\SupportedApps\Plex::class,
|
||||
'Portainer' => \App\SupportedApps\Portainer::class,
|
||||
'UniFi' => \App\SupportedApps\Unifi::class,
|
||||
'Sabnzbd' => \App\SupportedApps\Sabnzbd::class,
|
||||
];
|
||||
}
|
||||
public static function supportedOptions()
|
||||
{
|
||||
return array_keys(self::supportedList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope a query to only include pinned items.
|
||||
*
|
||||
@@ -53,45 +51,208 @@ class Item extends Model
|
||||
return $query->where('pinned', 1);
|
||||
}
|
||||
|
||||
public function getConfigAttribute()
|
||||
{
|
||||
$output = null;
|
||||
$view = null;
|
||||
if(isset($this->description) && !empty($this->description)){
|
||||
$output = json_decode($this->description);
|
||||
$output = is_object($output) ? $output : new \stdClass();
|
||||
if(isset($output->type) && !empty($output->type)) {
|
||||
$class = $output->type;
|
||||
$sap = new $class();
|
||||
$view = $sap->configDetails();
|
||||
$output->view = $view;
|
||||
}
|
||||
if(!isset($output->dataonly)) $output->dataonly = '0';
|
||||
|
||||
}
|
||||
return (object)$output;
|
||||
}
|
||||
public static function checkConfig($config)
|
||||
{
|
||||
// die(print_r($config));
|
||||
if(empty($config)) {
|
||||
$config = null;
|
||||
} else {
|
||||
$store = false;
|
||||
//die(var_dump($config));
|
||||
foreach($config as $key => $check) {
|
||||
if($key == 'type') continue;
|
||||
if($key == 'dataonly') continue;
|
||||
if(!empty($check) && $check != '0') {
|
||||
$store = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//die(var_dump($store))
|
||||
|
||||
$config['enabled'] = ($store) ? true : false;
|
||||
$config = json_encode($config);
|
||||
}
|
||||
return $config;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function tags()
|
||||
{
|
||||
$id = $this->id;
|
||||
$tags = ItemTag::select('tag_id')->where('item_id', $id)->pluck('tag_id')->toArray();
|
||||
$tagdetails = Item::select('id', 'title', 'url', 'pinned')->whereIn('id', $tags)->get();
|
||||
//print_r($tags);
|
||||
if(in_array(0, $tags)) {
|
||||
$details = new Item([
|
||||
"id" => 0,
|
||||
"title" => __('app.dashboard'),
|
||||
"url" => '',
|
||||
"pinned" => 0
|
||||
]);
|
||||
$tagdetails->prepend($details);
|
||||
}
|
||||
return $tagdetails;
|
||||
}
|
||||
|
||||
public function parents()
|
||||
{
|
||||
return $this->belongsToMany('App\Item', 'item_tag', 'item_id', 'tag_id');
|
||||
}
|
||||
public function children()
|
||||
{
|
||||
return $this->belongsToMany('App\Item', 'item_tag', 'tag_id', 'item_id');
|
||||
}
|
||||
|
||||
public function getLinkAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
return url('tag/'.$this->url);
|
||||
} else {
|
||||
return $this->url;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDroppableAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
return ' droppable';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function getLinkTargetAttribute()
|
||||
{
|
||||
$target = Setting::fetch('window_target');
|
||||
|
||||
if((int)$this->type === 1 || $target === 'current') {
|
||||
return '';
|
||||
} else {
|
||||
return ' target="' . $target . '"';
|
||||
}
|
||||
}
|
||||
|
||||
public function getLinkIconAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
return 'fa-tag';
|
||||
} else {
|
||||
return 'fa-arrow-alt-to-right';
|
||||
}
|
||||
}
|
||||
public function getLinkTypeAttribute()
|
||||
{
|
||||
if((int)$this->type === 1) {
|
||||
return 'tags';
|
||||
} else {
|
||||
return 'items';
|
||||
}
|
||||
}
|
||||
|
||||
public static function nameFromClass($class)
|
||||
{
|
||||
$explode = explode('\\', $class);
|
||||
$name = end($explode);
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function scopeOfType($query, $type)
|
||||
{
|
||||
switch($type) {
|
||||
case 'item':
|
||||
$typeid = 0;
|
||||
break;
|
||||
case 'tag':
|
||||
$typeid = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return $query->where('type', $typeid);
|
||||
}
|
||||
|
||||
public function enhanced()
|
||||
{
|
||||
/*if(isset($this->class) && !empty($this->class)) {
|
||||
$app = new $this->class;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return (bool)($app instanceof \App\EnhancedApps);*/
|
||||
return $this->description !== null;
|
||||
}
|
||||
|
||||
public static function isEnhanced($class)
|
||||
{
|
||||
if($class === null || $class === 'null') return false;
|
||||
$app = new $class;
|
||||
return (bool)($app instanceof \App\EnhancedApps);
|
||||
}
|
||||
|
||||
public static function isSearchProvider($class)
|
||||
{
|
||||
$app = new $class;
|
||||
return ((bool)($app instanceof \App\SearchInterface)) ? $app : false;
|
||||
}
|
||||
|
||||
public function enabled()
|
||||
{
|
||||
if($this->enhanced()) {
|
||||
$config = $this->getconfig();
|
||||
if($config) {
|
||||
return (bool) $config->enabled;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getconfig()
|
||||
{
|
||||
// $explode = explode('\\', $this->class);
|
||||
|
||||
|
||||
if(!isset($this->description) || empty($this->description)) {
|
||||
$config = new \stdClass;
|
||||
// $config->name = end($explode);
|
||||
$config->enabled = false;
|
||||
$config->override_url = null;
|
||||
$config->apikey = null;
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$config = json_decode($this->description);
|
||||
|
||||
// $config->name = end($explode);
|
||||
|
||||
|
||||
$config->url = $this->url;
|
||||
if(isset($config->override_url) && !empty($config->override_url)) {
|
||||
$config->url = $config->override_url;
|
||||
} else {
|
||||
$config->override_url = null;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public static function applicationDetails($class)
|
||||
{
|
||||
if(!empty($class)) {
|
||||
$name = self::nameFromClass($class);
|
||||
$application = Application::where('name', $name)->first();
|
||||
if($application) return $application;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public static function getApplicationDescription($class)
|
||||
{
|
||||
$details = self::applicationDetails($class);
|
||||
if($details !== false) {
|
||||
return $details->description.' - '.$details->license;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the item.
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
10
app/ItemTag.php
Normal file
10
app/ItemTag.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class ItemTag extends Pivot
|
||||
{
|
||||
|
||||
}
|
||||
46
app/Jobs/ProcessApps.php
Normal file
46
app/Jobs/ProcessApps.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Application;
|
||||
use App\SupportedApps;
|
||||
|
||||
class ProcessApps implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$localapps = Application::whereNull('class')->get();
|
||||
$json = SupportedApps::getList()->getBody();
|
||||
|
||||
Storage::disk('local')->put('supportedapps.json', $json);
|
||||
|
||||
foreach($localapps as $app) {
|
||||
$app->class = $app->class();
|
||||
$app->save();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,9 @@ use Illuminate\Support\ServiceProvider;
|
||||
use Artisan;
|
||||
use Schema;
|
||||
use App\Setting;
|
||||
use App\User;
|
||||
use App\Application;
|
||||
use App\Jobs\ProcessApps;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -16,44 +19,129 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$alt_bg = '';
|
||||
|
||||
if(!is_file(base_path('.env'))) {
|
||||
touch(base_path('.env'));
|
||||
Artisan::call('key:generate');
|
||||
copy(base_path('.env.example'), base_path('.env'));
|
||||
}
|
||||
$this->genKey();
|
||||
if(!is_file(database_path('app.sqlite'))) {
|
||||
// first time setup
|
||||
touch(database_path('app.sqlite'));
|
||||
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
|
||||
Artisan::call('storage:link');
|
||||
//Cache
|
||||
//Artisan::call('config:cache');
|
||||
//Artisan::call('route:cache');
|
||||
}
|
||||
if(is_file(database_path('app.sqlite'))) {
|
||||
if(Schema::hasTable('settings')) {
|
||||
if($bg_image = Setting::fetch('background_image')) {
|
||||
$alt_bg = ' style="background-image: url('.asset('storage/'.$bg_image).')"';
|
||||
}
|
||||
|
||||
// check version to see if an upgrade is needed
|
||||
$db_version = Setting::fetch('version');
|
||||
$db_version = Setting::_fetch('version');
|
||||
$app_version = config('app.version');
|
||||
if(version_compare($app_version, $db_version) == 1) { // app is higher than db, so need to run migrations etc
|
||||
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
|
||||
}
|
||||
|
||||
} else {
|
||||
Artisan::call('migrate', array('--path' => 'database/migrations', '--force' => true, '--seed' => true));
|
||||
}
|
||||
$lang = Setting::fetch('language');
|
||||
\App::setLocale($lang);
|
||||
|
||||
}
|
||||
view()->share('alt_bg', $alt_bg);
|
||||
|
||||
if(!is_file(public_path('storage/.gitignore'))) {
|
||||
Artisan::call('storage:link');
|
||||
\Session::put('current_user', null);
|
||||
}
|
||||
|
||||
$lang = Setting::fetch('language');
|
||||
\App::setLocale($lang);
|
||||
|
||||
|
||||
$applications = Application::all();
|
||||
if($applications->count() <= 0) {
|
||||
if (class_exists('ZipArchive')) {
|
||||
ProcessApps::dispatch();
|
||||
} else {
|
||||
die("You are missing php-zip");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// User specific settings need to go here as session isn't available at this point in the app
|
||||
view()->composer('*', function ($view)
|
||||
{
|
||||
|
||||
if(isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
|
||||
explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
|
||||
}
|
||||
if(!\Auth::check()) {
|
||||
if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])
|
||||
&& !empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
|
||||
$credentials = ['username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']];
|
||||
|
||||
if (\Auth::attempt($credentials, true)) {
|
||||
// Authentication passed...
|
||||
$user = \Auth::user();
|
||||
//\Session::put('current_user', $user);
|
||||
session(['current_user' => $user]);
|
||||
}
|
||||
}
|
||||
elseif(isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) {
|
||||
$user = User::where('username', $_SERVER['REMOTE_USER'])->first();
|
||||
if ($user) {
|
||||
\Auth::login($user, true);
|
||||
session(['current_user' => $user]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$alt_bg = '';
|
||||
if($bg_image = Setting::fetch('background_image')) {
|
||||
$alt_bg = ' style="background-image: url(storage/'.$bg_image.')"';
|
||||
}
|
||||
|
||||
$allusers = User::all();
|
||||
$current_user = User::currentUser();
|
||||
|
||||
$view->with('alt_bg', $alt_bg );
|
||||
$view->with('allusers', $allusers );
|
||||
$view->with('current_user', $current_user );
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
$this->app['view']->addNamespace('SupportedApps', app_path('SupportedApps'));
|
||||
|
||||
|
||||
if (env('FORCE_HTTPS') === true) {
|
||||
\URL::forceScheme('https');
|
||||
}
|
||||
|
||||
if(env('APP_URL') != 'http://localhost') {
|
||||
\URL::forceRootUrl(env('APP_URL'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate app key if missing and .env exists
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function genKey()
|
||||
{
|
||||
if(is_file(base_path('.env'))) {
|
||||
if(empty(env('APP_KEY'))) {
|
||||
Artisan::call('key:generate', array('--force' => true, '--no-interaction' => true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
|
||||
131
app/Search.php
Normal file
131
app/Search.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php namespace App;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
use App\Item;
|
||||
use App\Setting;
|
||||
use Form;
|
||||
use Cache;
|
||||
use Yaml;
|
||||
|
||||
abstract class Search
|
||||
{
|
||||
|
||||
/**
|
||||
* List of all search providers
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public static function providers()
|
||||
{
|
||||
$providers = self::standardProviders();
|
||||
$providers = $providers + self::appProviders();
|
||||
return collect($providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details for a single provider
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
public static function providerDetails($provider)
|
||||
{
|
||||
$providers = self::providers();
|
||||
if(!isset($providers[$provider])) return false;
|
||||
return (object)$providers[$provider] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of the standard providers
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public static function standardProviders()
|
||||
{
|
||||
// $providers = json_decode(file_get_contents(storage_path('app/searchproviders.json')));
|
||||
// print_r($providers);
|
||||
$providers = Yaml::parseFile(storage_path('app/searchproviders.yaml'));
|
||||
$all = [];
|
||||
foreach($providers as $key => $provider) {
|
||||
$all[$key] = $provider;
|
||||
$all[$key]['type'] = 'standard';
|
||||
}
|
||||
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through users apps to see if app is a search provider, might be worth
|
||||
* looking into caching this at some point
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public static function appProviders()
|
||||
{
|
||||
$providers = [];
|
||||
$userapps = Item::all();
|
||||
foreach($userapps as $app) {
|
||||
if(empty($app->class)) continue;
|
||||
if(($provider = Item::isSearchProvider($app->class)) !== false) {
|
||||
$name = Item::nameFromClass($app->class);
|
||||
$providers[$app->id] = [
|
||||
'id' => $app->id,
|
||||
'type' => $provider->type,
|
||||
'class' => $app->class,
|
||||
'url' => $app->url,
|
||||
'name' => $app->title,
|
||||
'colour' => $app->colour,
|
||||
'icon' => $app->icon,
|
||||
'description' => $app->description
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
return $providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the search form
|
||||
*
|
||||
* @return html
|
||||
*/
|
||||
public static function form()
|
||||
{
|
||||
$output = '';
|
||||
$homepage_search = Setting::fetch('homepage_search');
|
||||
$search_provider = Setting::where('key', '=', 'search_provider')->first();
|
||||
$user_search_provider = Setting::fetch('search_provider');
|
||||
//die(print_r($search_provider));
|
||||
|
||||
//die(var_dump($user_search_provider));
|
||||
// return early if search isn't applicable
|
||||
if((bool)$homepage_search !== true) return $output;
|
||||
$user_search_provider = $user_search_provider ?? 'none';
|
||||
|
||||
if((bool)$homepage_search && (bool)$search_provider) {
|
||||
|
||||
if((bool)$user_search_provider) {
|
||||
$name = 'app.options.'.$user_search_provider;
|
||||
$provider = self::providerDetails($user_search_provider);
|
||||
|
||||
$output .= '<div class="searchform">';
|
||||
$output .= '<form action="'.url('search').'"'.getLinkTargetAttribute().' method="get">';
|
||||
$output .= '<div id="search-container" class="input-container">';
|
||||
$output .= '<select name="provider">';
|
||||
foreach(self::providers() as $key => $searchprovider) {
|
||||
$selected = ((string)$key === (string)$user_search_provider) ? ' selected="selected"' : '';
|
||||
$output .= '<option value="'.$key.'"'.$selected.'>'.$searchprovider['name'].'</option>';
|
||||
}
|
||||
$output .= '</select>';
|
||||
$output .= Form::text('q', null, ['class' => 'homesearch', 'autofocus' => 'autofocus', 'placeholder' => __('app.settings.search').'...']);
|
||||
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
|
||||
$output .= '</div>';
|
||||
$output .= '</form>';
|
||||
$output .= '</div>';
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
10
app/SearchInterface.php
Normal file
10
app/SearchInterface.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php namespace App;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
interface SearchInterface
|
||||
{
|
||||
public function getResults($query, $providerdetails);
|
||||
|
||||
}
|
||||
133
app/Setting.php
133
app/Setting.php
@@ -5,6 +5,10 @@ namespace App;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Form;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\User;
|
||||
use App\Search;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Setting extends Model
|
||||
{
|
||||
@@ -36,16 +40,22 @@ class Setting extends Model
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getInput()
|
||||
public static function getInput(Request $request)
|
||||
{
|
||||
return (object) [
|
||||
'value' => Input::get('value'),
|
||||
'image' => Input::file('value'),
|
||||
'value' => $request->input('value'),
|
||||
'image' => $request->file('value'),
|
||||
];
|
||||
}
|
||||
|
||||
public function getListValueAttribute()
|
||||
{
|
||||
if((bool)$this->system === true) {
|
||||
$value = self::_fetch($this->key);
|
||||
} else {
|
||||
$value = self::fetch($this->key);
|
||||
}
|
||||
$this->value = $value;
|
||||
switch($this->type) {
|
||||
case 'image':
|
||||
if(!empty($this->value)) {
|
||||
@@ -64,6 +74,9 @@ class Setting extends Model
|
||||
case 'select':
|
||||
if(!empty($this->value) && $this->value !== 'none') {
|
||||
$options = (array)json_decode($this->options);
|
||||
if($this->key === 'search_provider') {
|
||||
$options = Search::providers()->pluck('name', 'id')->toArray();
|
||||
}
|
||||
$value = __($options[$this->value]);
|
||||
} else {
|
||||
$value = __('app.options.none');
|
||||
@@ -80,6 +93,12 @@ class Setting extends Model
|
||||
|
||||
public function getEditValueAttribute()
|
||||
{
|
||||
if((bool)$this->system === true) {
|
||||
$value = self::_fetch($this->key);
|
||||
} else {
|
||||
$value = self::fetch($this->key);
|
||||
}
|
||||
$this->value = $value;
|
||||
switch($this->type) {
|
||||
case 'image':
|
||||
$value = '';
|
||||
@@ -106,11 +125,17 @@ class Setting extends Model
|
||||
break;
|
||||
case 'select':
|
||||
$options = json_decode($this->options);
|
||||
if($this->key === 'search_provider') {
|
||||
$options = Search::providers()->pluck('name', 'id');
|
||||
}
|
||||
foreach($options as $key => $opt) {
|
||||
$options->$key = __($opt);
|
||||
}
|
||||
$value = Form::select('value', $options, null, ['class' => 'form-control']);
|
||||
break;
|
||||
case 'textarea':
|
||||
$value = Form::textarea('value', null, ['class' => 'form-control', 'cols' => '44', 'rows' => '15']);
|
||||
break;
|
||||
default:
|
||||
$value = Form::text('value', null, ['class' => 'form-control']);
|
||||
break;
|
||||
@@ -125,6 +150,7 @@ class Setting extends Model
|
||||
return $this->belongsTo('App\SettingGroup', 'group_id');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
@@ -132,20 +158,54 @@ class Setting extends Model
|
||||
*/
|
||||
public static function fetch($key)
|
||||
{
|
||||
if (Setting::cached($key)) {
|
||||
return Setting::$cache[$key];
|
||||
} else {
|
||||
$user = self::user();
|
||||
return self::_fetch($key, $user);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function _fetch($key, $user=null)
|
||||
{
|
||||
#$cachekey = ($user === null) ? $key : $key.'-'.$user->id;
|
||||
#if (Setting::cached($cachekey)) {
|
||||
# return Setting::$cache[$cachekey];
|
||||
#} else {
|
||||
$find = self::where('key', '=', $key)->first();
|
||||
|
||||
if (!is_null($find)) {
|
||||
$value = $find->value;
|
||||
Setting::add($key, $value);
|
||||
if((bool)$find->system === true) { // if system variable use global value
|
||||
$value = $find->value;
|
||||
} else { // not system variable so use user specific value
|
||||
// check if user specified value has been set
|
||||
//print_r($user);
|
||||
$usersetting = $user->settings()->where('id', $find->id)->first();
|
||||
//print_r($user->settings);
|
||||
//die(var_dump($usersetting));
|
||||
//->pivot->value;
|
||||
//echo "user: ".$user->id." --- ".$usersettings;
|
||||
if(isset($usersetting) && !empty($usersetting)) {
|
||||
$value = $usersetting->pivot->uservalue;
|
||||
} else { // if not get default from base setting
|
||||
//$user->settings()->save($find, ['value' => $find->value]);
|
||||
#$has_setting = $user->settings()->where('id', $find->id)->exists();
|
||||
#if($has_setting) {
|
||||
# $user->settings()->updateExistingPivot($find->id, ['uservalue' => (string)$find->value]);
|
||||
#} else {
|
||||
# $user->settings()->save($find, ['uservalue' => (string)$find->value]);
|
||||
#}
|
||||
$value = $find->value;
|
||||
}
|
||||
|
||||
}
|
||||
#Setting::add($cachekey, $value);
|
||||
|
||||
return $value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,52 +227,19 @@ class Setting extends Model
|
||||
return array_key_exists($key, Setting::$cache);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return html
|
||||
* The users that belong to the setting.
|
||||
*/
|
||||
public static function search()
|
||||
public function users()
|
||||
{
|
||||
$output = '';
|
||||
$homepage_search = self::fetch('homepage_search');
|
||||
$search_provider = self::where('key', '=', 'search_provider')->first();
|
||||
|
||||
//die(var_dump($search_provider->value));
|
||||
// return early if search isn't applicable
|
||||
if((bool)$homepage_search !== true) return $output;
|
||||
if($search_provider->value === 'none') return $output;
|
||||
if(empty($search_provider->value)) return $output;
|
||||
if(is_null($search_provider->value)) return $output;
|
||||
|
||||
|
||||
if((bool)$homepage_search && (bool)$search_provider) {
|
||||
|
||||
$options = (array)json_decode($search_provider->options);
|
||||
$name = $options[$search_provider->value];
|
||||
if((bool)$search_provider->value) {
|
||||
switch($search_provider->value) {
|
||||
case 'google':
|
||||
$url = 'https://www.google.com/search';
|
||||
$var = 'q';
|
||||
break;
|
||||
case 'ddg':
|
||||
$url = 'https://duckduckgo.com/';
|
||||
$var = 'q';
|
||||
break;
|
||||
case 'bing':
|
||||
$url = 'https://www.bing.com/search';
|
||||
$var = 'q';
|
||||
break;
|
||||
}
|
||||
$output .= '<div class="searchform">';
|
||||
$output .= Form::open(['url' => $url, 'method' => 'get']);
|
||||
$output .= '<div class="input-container">';
|
||||
$output .= Form::text($var, null, ['class' => 'homesearch', 'placeholder' => __($name).' '.__('app.settings.search').'...']);
|
||||
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
|
||||
$output .= '</div>';
|
||||
$output .= Form::close();
|
||||
$output .= '</div>';
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
return $this->belongsToMany('App\User')->using('App\SettingUser')->withPivot('uservalue');
|
||||
}
|
||||
|
||||
public static function user()
|
||||
{
|
||||
return User::currentUser();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
10
app/SettingUser.php
Normal file
10
app/SettingUser.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class SettingUser extends Pivot
|
||||
{
|
||||
//
|
||||
}
|
||||
167
app/SupportedApps.php
Normal file
167
app/SupportedApps.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php namespace App;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
abstract class SupportedApps
|
||||
{
|
||||
|
||||
protected $jar = false;
|
||||
protected $method = 'GET';
|
||||
protected $error;
|
||||
|
||||
public function appTest($url, $attrs = [], $overridevars=false)
|
||||
{
|
||||
if(empty($this->config->url)) {
|
||||
return (object)[
|
||||
'code' => 404,
|
||||
'status' => 'No URL has been specified',
|
||||
'response' => 'No URL has been specified',
|
||||
];
|
||||
}
|
||||
$res = $this->execute($url, $attrs);
|
||||
if($res == null) {
|
||||
return (object)[
|
||||
'code' => null,
|
||||
'status' => $this->error,
|
||||
'response' => 'Connection failed',
|
||||
];
|
||||
}
|
||||
switch($res->getStatusCode()) {
|
||||
case 200:
|
||||
$status = 'Successfully communicated with the API';
|
||||
break;
|
||||
case 401:
|
||||
$status = 'Failed: Invalid credentials';
|
||||
break;
|
||||
case 404:
|
||||
$status = 'Failed: Please make sure your URL is correct and that there is a trailing slash';
|
||||
break;
|
||||
default:
|
||||
$status = 'Something went wrong... Code: '.$res->getStatusCode();
|
||||
break;
|
||||
}
|
||||
return (object)[
|
||||
'code' => $res->getStatusCode(),
|
||||
'status' => $status,
|
||||
'response' => $res->getBody(),
|
||||
];
|
||||
}
|
||||
|
||||
public function execute($url, $attrs = [], $overridevars=false, $overridemethod=false)
|
||||
{
|
||||
$res = null;
|
||||
|
||||
$vars = ($overridevars !== false) ?
|
||||
$overridevars : [
|
||||
'http_errors' => false,
|
||||
'timeout' => 15,
|
||||
'connect_timeout' => 15,
|
||||
];
|
||||
|
||||
$client = new Client($vars);
|
||||
|
||||
$method = ($overridemethod !== false) ? $overridemethod : $this->method;
|
||||
|
||||
try {
|
||||
return $client->request($method, $url, $attrs);
|
||||
} catch (\GuzzleHttp\Exception\ConnectException $e) {
|
||||
Log::error("Connection refused");
|
||||
Log::debug($e->getMessage());
|
||||
$this->error = "Connection refused - ".(string) $e->getMessage();
|
||||
} catch (\GuzzleHttp\Exception\ServerException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
$this->error = (string) $e->getResponse()->getBody();
|
||||
}
|
||||
$this->error = 'General error connecting with API';
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function login()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function normaliseurl($url, $addslash=true)
|
||||
{
|
||||
|
||||
$url = rtrim($url, '/');
|
||||
if($addslash) $url .= '/';
|
||||
|
||||
return $url;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getLiveStats($status, $data)
|
||||
{
|
||||
$className = get_class($this);
|
||||
$explode = explode('\\', $className);
|
||||
$name = end($explode);
|
||||
|
||||
$html = view('SupportedApps::'.$name.'.livestats', $data)->with('data', $data)->render();
|
||||
return json_encode(['status' => $status, 'html' => $html]);
|
||||
//return
|
||||
}
|
||||
|
||||
public static function getList()
|
||||
{
|
||||
// $list_url = 'https://apps.heimdall.site/list';
|
||||
$list_url = config('app.appsource').'list.json';
|
||||
$client = new Client(['http_errors' => false, 'timeout' => 15, 'connect_timeout' => 15]);
|
||||
return $client->request('GET', $list_url);
|
||||
}
|
||||
|
||||
public static function configValue($item=null, $key=null)
|
||||
{
|
||||
if(isset($item) && !empty($item)) {
|
||||
return $item->getconfig()->$key;
|
||||
} else return null;
|
||||
}
|
||||
|
||||
public static function getFiles($app)
|
||||
{
|
||||
$zipurl = config('app.appsource').'files/'.$app->sha.'.zip';
|
||||
|
||||
$client = new Client(['http_errors' => false, 'timeout' => 60, 'connect_timeout' => 15]);
|
||||
$res = $client->request('GET', $zipurl);
|
||||
|
||||
if(!file_exists(app_path('SupportedApps'))) {
|
||||
mkdir(app_path('SupportedApps'), 0777, true);
|
||||
}
|
||||
|
||||
$src = app_path('SupportedApps/'.className($app->name).'.zip');
|
||||
file_put_contents($src, $res->getBody());
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$x = $zip->open($src); // open the zip file to extract
|
||||
if ($x === true) {
|
||||
$zip->extractTo(app_path('SupportedApps')); // place in the directory with same name
|
||||
$zip->close();
|
||||
unlink($src); //Deleting the Zipped file
|
||||
} else {
|
||||
var_dump($x);
|
||||
}
|
||||
}
|
||||
|
||||
public static function saveApp($details, $app)
|
||||
{
|
||||
$app->appid = $details->appid;
|
||||
$app->name = $details->name;
|
||||
$app->sha = $details->sha ?? null;
|
||||
$app->icon = 'icons/'.$details->icon;
|
||||
$app->website = $details->website;
|
||||
$app->license = $details->license;
|
||||
|
||||
$appclass = $app->class();
|
||||
$application = new $appclass;
|
||||
$enhanced = (bool)($application instanceof \App\EnhancedApps);
|
||||
$app->class = $appclass;
|
||||
$app->enhanced = $enhanced;
|
||||
$app->tile_background = $details->tile_background;
|
||||
$app->save();
|
||||
return $app;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php namespace App\SupportedApps\Contracts;
|
||||
|
||||
interface Applications {
|
||||
|
||||
public function defaultColour();
|
||||
|
||||
public function icon();
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php namespace App\SupportedApps\Contracts;
|
||||
|
||||
interface Livestats {
|
||||
|
||||
public function configDetails();
|
||||
|
||||
public function testConfig();
|
||||
|
||||
public function executeConfig();
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Duplicati implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#2c3744';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/duplicati.png';
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Emby implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#222';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/emby.png';
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class Nzbget implements Contracts\Applications, Contracts\Livestats {
|
||||
|
||||
public $config;
|
||||
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#253827';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/nzbget.png';
|
||||
}
|
||||
public function configDetails()
|
||||
{
|
||||
return 'nzbget';
|
||||
}
|
||||
public function testConfig()
|
||||
{
|
||||
$res = $this->buildRequest('status');
|
||||
switch($res->getStatusCode()) {
|
||||
case 200:
|
||||
echo 'Successfully connected to the API';
|
||||
break;
|
||||
case 401:
|
||||
echo 'Failed: Invalid credentials';
|
||||
break;
|
||||
case 404:
|
||||
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
|
||||
break;
|
||||
default:
|
||||
echo 'Something went wrong... Code: '.$res->getStatusCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
public function executeConfig()
|
||||
{
|
||||
$output = '';
|
||||
$res = $this->buildRequest('status');
|
||||
$data = json_decode($res->getBody());
|
||||
//$data->result->RemainingSizeMB = '10000000';
|
||||
//$data->result->DownloadRate = '100000000';
|
||||
$size = $data->result->RemainingSizeMB;
|
||||
$rate = $data->result->DownloadRate;
|
||||
$queue_size = format_bytes($size*1000*1000, false, ' <span>', '</span>');
|
||||
$current_speed = format_bytes($rate, false, ' <span>');
|
||||
|
||||
if($size > 0 || $rate > 0) {
|
||||
$output = '
|
||||
<ul class="livestats">
|
||||
<li><span class="title">Queue</span><strong>'.$queue_size.'</strong></li>
|
||||
<li><span class="title">Speed</span><strong>'.$current_speed.'/s</span></strong></li>
|
||||
</ul>
|
||||
';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
public function buildRequest($endpoint)
|
||||
{
|
||||
$config = $this->config;
|
||||
$url = $config->url;
|
||||
$username = $config->username;
|
||||
$password = $config->password;
|
||||
|
||||
$rebuild_url = str_replace('http://', 'http://'.$username.':'.$password.'@', $url);
|
||||
$rebuild_url = str_replace('https://', 'https://'.$username.':'.$password.'@', $rebuild_url);
|
||||
|
||||
$api_url = $rebuild_url.'jsonrpc/'.$endpoint;
|
||||
|
||||
$client = new Client(['http_errors' => false]);
|
||||
$res = $client->request('GET', $api_url);
|
||||
return $res;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Pfsense implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#4e4742';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/pfsense.png';
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class Pihole implements Contracts\Applications, Contracts\Livestats {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#352222';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/pihole.png';
|
||||
}
|
||||
|
||||
public function configDetails()
|
||||
{
|
||||
return 'pihole';
|
||||
}
|
||||
|
||||
public function testConfig()
|
||||
{
|
||||
$res = $this->buildRequest();
|
||||
switch($res->getStatusCode()) {
|
||||
case 200:
|
||||
echo 'Successfully connected to the API';
|
||||
break;
|
||||
case 401:
|
||||
echo 'Failed: Invalid credentials';
|
||||
break;
|
||||
case 404:
|
||||
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
|
||||
break;
|
||||
default:
|
||||
echo 'Something went wrong... Code: '.$res->getStatusCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function executeConfig()
|
||||
{
|
||||
$output = '';
|
||||
$res = $this->buildRequest();
|
||||
$data = json_decode($res->getBody());
|
||||
|
||||
$output = '
|
||||
<ul class="livestats">
|
||||
<li><span class="title">Domains<br />Blocked</span><strong>'.$data->domains_being_blocked.'</strong></li>
|
||||
<li><span class="title">Blocked<br />Today</span><strong>'.$data->ads_blocked_today.'</span></strong></li>
|
||||
</ul>
|
||||
';
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function buildRequest()
|
||||
{
|
||||
$config = $this->config;
|
||||
$url = $config->url;
|
||||
|
||||
$api_url = $url.'admin/api.php';
|
||||
//die( $api_url.' --- ');
|
||||
|
||||
$client = new Client(['http_errors' => false]);
|
||||
$res = $client->request('GET', $api_url);
|
||||
return $res;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Plex implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#222';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/plex.png';
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Portainer implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#283f44';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/portainer.png';
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class Sabnzbd implements Contracts\Applications, Contracts\Livestats {
|
||||
|
||||
public $config;
|
||||
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#3e3924';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/sabnzbd.png';
|
||||
}
|
||||
public function configDetails()
|
||||
{
|
||||
return 'sabnzbd';
|
||||
}
|
||||
public function testConfig()
|
||||
{
|
||||
$res = $this->buildRequest('queue');
|
||||
switch($res->getStatusCode()) {
|
||||
case 200:
|
||||
$data = json_decode($res->getBody());
|
||||
if(isset($data->error) && !empty($data->error)) {
|
||||
echo 'Failed: '.$data->error;
|
||||
} else {
|
||||
echo 'Successfully connected to the API';
|
||||
}
|
||||
break;
|
||||
case 401:
|
||||
echo 'Failed: Invalid credentials';
|
||||
break;
|
||||
case 404:
|
||||
echo 'Failed: Please make sure your URL is correct and that there is a trailing slash';
|
||||
break;
|
||||
default:
|
||||
echo 'Something went wrong... Code: '.$res->getStatusCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
public function executeConfig()
|
||||
{
|
||||
$output = '';
|
||||
$res = $this->buildRequest('queue');
|
||||
$data = json_decode($res->getBody());
|
||||
//$data->result->RemainingSizeMB = '10000000';
|
||||
//$data->result->DownloadRate = '100000000';
|
||||
$size = $data->queue->mbleft;
|
||||
$rate = $data->queue->kbpersec;
|
||||
$queue_size = format_bytes($size*1000*1000, false, ' <span>', '</span>');
|
||||
$current_speed = format_bytes($rate*1000, false, ' <span>');
|
||||
|
||||
if($size > 0 || $rate > 0) {
|
||||
$output = '
|
||||
<ul class="livestats">
|
||||
<li><span class="title">Queue</span><strong>'.$queue_size.'</strong></li>
|
||||
<li><span class="title">Speed</span><strong>'.$current_speed.'/s</span></strong></li>
|
||||
</ul>
|
||||
';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
public function buildRequest($endpoint)
|
||||
{
|
||||
$config = $this->config;
|
||||
$url = $config->url;
|
||||
$apikey = $config->apikey;
|
||||
|
||||
$api_url = $url.'api?output=json&apikey='.$apikey.'&mode='.$endpoint;
|
||||
//die( $api_url.' --- ');
|
||||
|
||||
$client = new Client(['http_errors' => false]);
|
||||
$res = $client->request('GET', $api_url);
|
||||
return $res;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php namespace App\SupportedApps;
|
||||
|
||||
class Unifi implements Contracts\Applications {
|
||||
public function defaultColour()
|
||||
{
|
||||
return '#363840';
|
||||
}
|
||||
public function icon()
|
||||
{
|
||||
return 'supportedapps/unifi.png';
|
||||
}
|
||||
}
|
||||
36
app/User.php
36
app/User.php
@@ -15,7 +15,7 @@ class User extends Authenticatable
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name', 'email', 'password',
|
||||
'username', 'email', 'password',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -26,4 +26,38 @@ class User extends Authenticatable
|
||||
protected $hidden = [
|
||||
'password', 'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the items for the user.
|
||||
*/
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany('App\Item');
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings that belong to the user.
|
||||
*/
|
||||
public function settings()
|
||||
{
|
||||
return $this->belongsToMany('App\Setting')->withPivot('uservalue');
|
||||
}
|
||||
|
||||
public static function currentUser()
|
||||
{
|
||||
$current_user = session('current_user');
|
||||
if ($current_user) { // if logged in, set this user
|
||||
return $current_user;
|
||||
} else { // not logged in, get first user
|
||||
$user = User::where('public_front',true)->first();
|
||||
if(!$user) {
|
||||
$user = User::first();
|
||||
}
|
||||
session(['current_user' => $user]);
|
||||
return $user;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
"license": "MIT",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"fideloper/proxy": "~3.3",
|
||||
"guzzlehttp/guzzle": "^6.3",
|
||||
"laravel/framework": "5.5.*",
|
||||
"laravel/tinker": "~1.0",
|
||||
"laravelcollective/html": "^5.5"
|
||||
"php": ">=7.2.5",
|
||||
"fideloper/proxy": "^4.0",
|
||||
"graham-campbell/github": "^10.5",
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"laravel/framework": "^7.0",
|
||||
"laravel/tinker": "^2.0",
|
||||
"laravel/ui": "^2.4",
|
||||
"laravelcollective/html": "^6.0",
|
||||
"symfony/yaml": "^5.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"filp/whoops": "~2.0",
|
||||
@@ -57,6 +60,10 @@
|
||||
"config": {
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"optimize-autoloader": true
|
||||
"optimize-autoloader": true,
|
||||
"allow-plugins": {
|
||||
"kylekatarnls/update-helper": true,
|
||||
"symfony/thanks": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5937
composer.lock
generated
5937
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ return [
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Heimdall'),
|
||||
'version' => '1.3.0',
|
||||
'version' => '2.4.0',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -54,6 +54,8 @@ return [
|
||||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
'appsource' => env('APP_SOURCE', 'https://appslist.heimdall.site/'),
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -228,6 +230,10 @@ return [
|
||||
'URL' => Illuminate\Support\Facades\URL::class,
|
||||
'Validator' => Illuminate\Support\Facades\Validator::class,
|
||||
'View' => Illuminate\Support\Facades\View::class,
|
||||
'Yaml' => Symfony\Component\Yaml\Yaml::class,
|
||||
|
||||
'SupportedApps' => App\SupportedApps::class,
|
||||
'EnhancedApps' => App\EnhancedApps::class,
|
||||
|
||||
],
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@@ -107,13 +109,27 @@ return [
|
||||
|
||||
'redis' => [
|
||||
|
||||
'client' => 'predis',
|
||||
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||
|
||||
'options' => [
|
||||
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
|
||||
],
|
||||
|
||||
'default' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'port' => env('REDIS_PORT', 6379),
|
||||
'database' => 0,
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
],
|
||||
|
||||
'cache' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_CACHE_DB', '1'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
91
config/github.php
Normal file
91
config/github.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Laravel GitHub.
|
||||
*
|
||||
* (c) Graham Campbell <graham@alt-three.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which of the connections below you wish to use as
|
||||
| your default connection for all work. Of course, you may use many
|
||||
| connections at once using the manager class.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => 'main',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| GitHub Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here are each of the connections setup for your application. Example
|
||||
| configuration has been included, but you may add as many connections as
|
||||
| you would like. Note that the 5 supported authentication methods are:
|
||||
| "application", "jwt", "none", "password", and "token".
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'main' => [
|
||||
'token' => 'your-token',
|
||||
'method' => 'token',
|
||||
// 'backoff' => false,
|
||||
// 'cache' => false,
|
||||
// 'version' => 'v3',
|
||||
// 'enterprise' => false,
|
||||
],
|
||||
|
||||
'app' => [
|
||||
'clientId' => 'your-client-id',
|
||||
'clientSecret' => 'your-client-secret',
|
||||
'method' => 'application',
|
||||
// 'backoff' => false,
|
||||
// 'cache' => false,
|
||||
// 'version' => 'v3',
|
||||
// 'enterprise' => false,
|
||||
],
|
||||
|
||||
'jwt' => [
|
||||
'token' => 'your-jwt-token',
|
||||
'method' => 'jwt',
|
||||
// 'backoff' => false,
|
||||
// 'cache' => false,
|
||||
// 'version' => 'v3',
|
||||
// 'enterprise' => false,
|
||||
],
|
||||
|
||||
'other' => [
|
||||
'username' => 'your-username',
|
||||
'password' => 'your-password',
|
||||
'method' => 'password',
|
||||
// 'backoff' => false,
|
||||
// 'cache' => false,
|
||||
// 'version' => 'v3',
|
||||
// 'enterprise' => false,
|
||||
],
|
||||
|
||||
'none' => [
|
||||
'method' => 'none',
|
||||
// 'backoff' => false,
|
||||
// 'cache' => false,
|
||||
// 'version' => 'v3',
|
||||
// 'enterprise' => false,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
104
config/logging.php
Normal file
104
config/logging.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\SyslogUdpHandler;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default log channel that gets used when writing
|
||||
| messages to the logs. The name specified in this option should match
|
||||
| one of the channels defined in the "channels" configuration array.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LOG_CHANNEL', 'stack'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Channels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log channels for your application. Out of
|
||||
| the box, Laravel uses the Monolog PHP logging library. This gives
|
||||
| you a variety of powerful log handlers / formatters to utilize.
|
||||
|
|
||||
| Available Drivers: "single", "daily", "slack", "syslog",
|
||||
| "errorlog", "monolog",
|
||||
| "custom", "stack"
|
||||
|
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => ['single'],
|
||||
'ignore_exceptions' => false,
|
||||
],
|
||||
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => 'debug',
|
||||
'days' => 14,
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'driver' => 'slack',
|
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||
'username' => 'Laravel Log',
|
||||
'emoji' => ':boom:',
|
||||
'level' => 'critical',
|
||||
],
|
||||
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => 'debug',
|
||||
'handler' => SyslogUdpHandler::class,
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_URL'),
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
],
|
||||
|
||||
'stderr' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => StreamHandler::class,
|
||||
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||
'with' => [
|
||||
'stream' => 'php://stderr',
|
||||
],
|
||||
],
|
||||
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => NullHandler::class,
|
||||
],
|
||||
|
||||
'emergency' => [
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
@@ -164,7 +164,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'secure' => env('SESSION_SECURE_COOKIE', false),
|
||||
'secure' => env('SESSION_SECURE_COOKIE', null),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
3698
css/app.css
vendored
Normal file
3698
css/app.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddColumnsToItemsForGroups extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->integer('type')->default(0)->index(); // 0 = item, 1 = category
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->dropColumn(['type']);
|
||||
});
|
||||
}
|
||||
}
|
||||
35
database/migrations/2018_02_16_193703_item_tag.php
Normal file
35
database/migrations/2018_02_16_193703_item_tag.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class ItemTag extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('item_tag', function (Blueprint $table) {
|
||||
$table->integer('item_id')->unsigned()->index();
|
||||
$table->foreign('item_id')->references('id')->on('items')->onDelete('cascade');
|
||||
|
||||
$table->integer('tag_id')->unsigned()->index();
|
||||
$table->foreign('tag_id')->references('id')->on('items')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('item_tag');
|
||||
}
|
||||
}
|
||||
38
database/migrations/2018_10_12_122907_create_users_table.php
Normal file
38
database/migrations/2018_10_12_122907_create_users_table.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateUsersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('username')->unique();
|
||||
$table->string('email');
|
||||
$table->string('avatar')->nullable();
|
||||
$table->string('password')->nullable();
|
||||
$table->string('autologin')->nullable()->index();
|
||||
$table->boolean('public_front')->default(false);
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreatePasswordResetsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('password_resets', function (Blueprint $table) {
|
||||
$table->string('email')->index();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('password_resets');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddUserIdToItemsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->integer('user_id')->default(1)->index(); // 0 = item, 1 = category
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->dropColumn(['user_id']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateSettingUserPivotTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('setting_user', function (Blueprint $table) {
|
||||
$table->integer('setting_id')->unsigned()->index();
|
||||
$table->foreign('setting_id')->references('id')->on('settings')->onDelete('cascade');
|
||||
$table->integer('user_id')->unsigned()->index();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->primary(['setting_id', 'user_id']);
|
||||
$table->string('uservalue')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('setting_user');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateApplicationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('applications', function (Blueprint $table) {
|
||||
|
||||
$table->string('appid')->unique();
|
||||
$table->string('name')->unique();
|
||||
$table->string('sha')->unique()->nullable();
|
||||
$table->string('icon')->nullable();
|
||||
$table->string('website')->nullable();
|
||||
$table->string('license')->nullable();
|
||||
$table->mediumText('description')->nullable();
|
||||
$table->boolean('enhanced')->default(false);
|
||||
$table->string('tile_background')->default('dark');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('applications');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddClassToItemsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->string('class')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->dropColumn(['class']);
|
||||
});
|
||||
}
|
||||
}
|
||||
36
database/migrations/2018_10_31_191604_create_jobs_table.php
Normal file
36
database/migrations/2018_10_31_191604_create_jobs_table.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateJobsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateFailedJobsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
}
|
||||
32
database/migrations/2022_03_15_140911_add_appid_to_items.php
Normal file
32
database/migrations/2022_03_15_140911_add_appid_to_items.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddAppidToItems extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->string('appid')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->dropColumn(['appid']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddClassToApplication extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->string('class')->nullable()->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->dropColumn(['class']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddAppDescriptionToItems extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
$table->text('appdescription')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('items', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -12,5 +12,6 @@ class DatabaseSeeder extends Seeder
|
||||
public function run()
|
||||
{
|
||||
$this->call(SettingsSeeder::class);
|
||||
$this->call(UsersSeeder::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,16 @@ class SettingsSeeder extends Seeder
|
||||
$setting_group->title = 'app.settings.miscellaneous';
|
||||
$setting_group->save();
|
||||
}
|
||||
if(!$setting_group = SettingGroup::find(4)) {
|
||||
$setting_group = new SettingGroup;
|
||||
$setting_group->id = 4;
|
||||
$setting_group->title = 'app.settings.advanced';
|
||||
$setting_group->order = 3;
|
||||
$setting_group->save();
|
||||
} else {
|
||||
$setting_group->title = 'app.settings.advanced';
|
||||
$setting_group->save();
|
||||
}
|
||||
|
||||
if($version = Setting::find(1)) {
|
||||
$version->label = 'app.settings.version';
|
||||
@@ -90,11 +100,13 @@ class SettingsSeeder extends Seeder
|
||||
'none' => 'app.options.none',
|
||||
'google' => 'app.options.google',
|
||||
'ddg' => 'app.options.ddg',
|
||||
'bing' => 'app.options.bing'
|
||||
'qwant' => 'app.options.qwant',
|
||||
'bing' => 'app.options.bing',
|
||||
'startpage' => 'app.options.startpage',
|
||||
]);
|
||||
|
||||
if(!$setting = Setting::find(4)) {
|
||||
|
||||
|
||||
$setting = new Setting;
|
||||
$setting->id = 4;
|
||||
$setting->group_id = 3;
|
||||
@@ -115,6 +127,10 @@ class SettingsSeeder extends Seeder
|
||||
'en' => 'English',
|
||||
'fi' => 'Suomi (Finnish)',
|
||||
'fr' => 'Français (French)',
|
||||
'el' => 'Ελληνικά (Greek)',
|
||||
'it' => 'Italiano (Italian)',
|
||||
'no' => 'Norsk (Norwegian)',
|
||||
'pl' => 'Polski (Polish)',
|
||||
'sv' => 'Svenska (Swedish)',
|
||||
'es' => 'Español (Spanish)',
|
||||
'tr' => 'Türkçe (Turkish)',
|
||||
@@ -134,6 +150,109 @@ class SettingsSeeder extends Seeder
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
$window_target_options = json_encode([
|
||||
'current' => 'app.settings.window_target.current',
|
||||
'heimdall' => 'app.settings.window_target.one',
|
||||
'_blank' => 'app.settings.window_target.new',
|
||||
]);
|
||||
|
||||
if(!$setting = Setting::find(7)) {
|
||||
|
||||
$setting = new Setting;
|
||||
$setting->id = 7;
|
||||
$setting->group_id = 3;
|
||||
$setting->key = 'window_target';
|
||||
$setting->type = 'select';
|
||||
$setting->options = $window_target_options;
|
||||
$setting->label = 'app.settings.window_target';
|
||||
$setting->value = 'heimdall';
|
||||
$setting->save();
|
||||
} else {
|
||||
$setting->options = $window_target_options;
|
||||
$setting->label = 'app.settings.window_target';
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if($support = Setting::find(8)) {
|
||||
$support->label = 'app.settings.support';
|
||||
$support->value = '<a rel="noopener" target="_blank" href="https://discord.gg/CCjHKn4">Discord</a> | <a rel="noopener" target="_blank" href="https://github.com/linuxserver/Heimdall">Github</a> | <a rel="noopener" target="_blank" href="https://blog.heimdall.site/">Blog</a>';
|
||||
$support->save();
|
||||
} else {
|
||||
$setting = new Setting;
|
||||
$setting->id = 8;
|
||||
$setting->group_id = 1;
|
||||
$setting->key = 'support';
|
||||
$setting->type = 'text';
|
||||
$setting->label = 'app.settings.support';
|
||||
$setting->value = '<a rel="noopener" target="_blank" href="https://discord.gg/CCjHKn4">Discord</a> | <a rel="noopener" target="_blank" href="https://github.com/linuxserver/Heimdall">Github</a> | <a rel="noopener" target="_blank" href="https://blog.heimdall.site/">Blog</a>';
|
||||
$setting->system = true;
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if($donate = Setting::find(9)) {
|
||||
$donate->label = 'app.settings.donate';
|
||||
$donate->value = '<a rel="noopener" target="_blank" href="https://www.paypal.me/heimdall">Paypal</a>';
|
||||
$donate->save();
|
||||
} else {
|
||||
$setting = new Setting;
|
||||
$setting->id = 9;
|
||||
$setting->group_id = 1;
|
||||
$setting->key = 'donate';
|
||||
$setting->type = 'text';
|
||||
$setting->label = 'app.settings.donate';
|
||||
$setting->value = '<a rel="noopener" target="_blank" href="https://www.paypal.me/heimdall">Paypal</a>';
|
||||
$setting->system = true;
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if(!$setting = Setting::find(10)) {
|
||||
$setting = new Setting;
|
||||
$setting->id = 10;
|
||||
$setting->group_id = 4;
|
||||
$setting->key = 'custom_css';
|
||||
$setting->type = 'textarea';
|
||||
$setting->label = 'app.settings.custom_css';
|
||||
$setting->value = '';
|
||||
$setting->save();
|
||||
} else {
|
||||
$setting->type = 'textarea';
|
||||
$setting->group_id = 4;
|
||||
$setting->label = 'app.settings.custom_css';
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if(!$setting = Setting::find(11)) {
|
||||
$setting = new Setting;
|
||||
$setting->id = 11;
|
||||
$setting->group_id = 4;
|
||||
$setting->key = 'custom_js';
|
||||
$setting->type = 'textarea';
|
||||
$setting->label = 'app.settings.custom_js';
|
||||
$setting->value = '';
|
||||
$setting->save();
|
||||
} else {
|
||||
$setting->type = 'textarea';
|
||||
$setting->group_id = 4;
|
||||
$setting->label = 'app.settings.custom_js';
|
||||
$setting->save();
|
||||
}
|
||||
|
||||
if(!$home_tag = \App\Item::find(0)) {
|
||||
$home_tag = new \App\Item;
|
||||
$home_tag->id = 0;
|
||||
$home_tag->title = 'app.dashboard';
|
||||
$home_tag->pinned = 0;
|
||||
$home_tag->url = '';
|
||||
$home_tag->type = 1;
|
||||
$home_tag->user_id = 0;
|
||||
$home_tag->save();
|
||||
|
||||
$homeapps = \App\Item::withoutGlobalScope('user_id')->doesntHave('parents')->get();
|
||||
foreach($homeapps as $app) {
|
||||
if($app->id === 0) continue;
|
||||
$app->parents()->attach(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
27
database/seeds/UsersSeeder.php
Normal file
27
database/seeds/UsersSeeder.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\User;
|
||||
|
||||
class UsersSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// Groups
|
||||
if(!$user = User::find(1)) {
|
||||
$user = new User;
|
||||
$user->id = 1;
|
||||
$user->username = 'admin';
|
||||
$user->email = 'admin@test.com';
|
||||
$user->password = null;
|
||||
$user->save();
|
||||
} else {
|
||||
//$user->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
mix-manifest.json
Normal file
3
mix-manifest.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"/css/app.css": "/css/app.css"
|
||||
}
|
||||
15128
package-lock.json
generated
15128
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@@ -10,15 +10,14 @@
|
||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.17",
|
||||
"bootstrap-sass": "^3.3.7",
|
||||
"cross-env": "^5.1.3",
|
||||
"jquery": "^3.2",
|
||||
"laravel-mix": "^1.0",
|
||||
"lodash": "^4.17.4",
|
||||
"vue": "^2.5.7"
|
||||
"bootstrap-sass": "^3.4.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"jquery": "^3.4.1",
|
||||
"laravel-mix": "^4.0.16",
|
||||
"sass": "^1.21.0",
|
||||
"sass-loader": "7.*"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-sass": "^4.7.2"
|
||||
"select2": "^4.0.7"
|
||||
}
|
||||
}
|
||||
|
||||
5
public/css/all.min.css
vendored
Normal file
5
public/css/all.min.css
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/*!
|
||||
* Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license (Commercial License)
|
||||
*/
|
||||
.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-ban:before{content:"\f05e"}.fa-check:before{content:"\f00c"}.fa-cloud-download:before{content:"\f0ed"}.fa-cogs:before{content:"\f085"}.fa-edit:before{content:"\f044"}.fa-exchange:before{content:"\f0ec"}.fa-list:before{content:"\f03a"}.fa-pencil:before{content:"\f040"}.fa-plus:before{content:"\f067"}.fa-save:before{content:"\f0c7"}.fa-tag:before{content:"\f02b"}.fa-th:before{content:"\f00a"}.fa-thumbtack:before{content:"\f08d"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-user:before{content:"\f007"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Pro";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Pro";font-weight:900}
|
||||
5307
public/css/app.css
vendored
5307
public/css/app.css
vendored
File diff suppressed because it is too large
Load Diff
14
public/img/heimdall-logo-bloated.svg
Normal file
14
public/img/heimdall-logo-bloated.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="780" height="619" viewBox="0 0 780 619">
|
||||
<metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 ">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""/>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
|
||||
|
||||
|
||||
|
||||
<?xpacket end="w"?></metadata>
|
||||
<path class="cls-1" d="M440.227,415.119V390.2l8.552-26.577C508.647,304.3,555.686,248.776,564,231.691l-10.215,3.56s9.5-11.864,8.552-18.51c-7.6-116.273-73.17-176.862-91.226-191.732,26.607,31.955,19.326,42.4,19.326,42.4C478.714,45.576,454.64,24.377,449.888,19l-5.7,33.853c22.806,13.289,16.79,20.882,16.79,20.882C455.591,66.141,441.021,59.5,441.021,59.5l-1.586,9.491c6.973,3.165,38.327,22.149,38.565,70.872,0,59.323-33.735,74.985-39.674,77.357-19.718-11.865-41.1-11.627-46.326-12.1-5.226.474-26.608,0.236-46.324,12.1C339.735,214.844,306,199.182,306,139.859c0.238-48.723,31.6-67.707,38.564-70.872L342.983,59.5s-14.574,6.644-19.955,14.238c0,0-6.022-7.593,16.786-20.882L334.112,19c-4.752,5.378-28.824,26.577-40.543,48.407,0,0-7.288-10.443,19.32-42.4-18.054,14.87-83.625,75.459-91.226,191.732-0.95,6.646,8.554,18.51,8.554,18.51L220,231.691c8.316,17.085,55.355,72.612,115.221,131.935l8.554,26.577v24.916l-7.6-26.577L318.83,360.067v28.95C325.957,409.186,353.751,450,353.751,450V365.525L247.32,249.488s66.52,54.1,85.526,73.56l9.978-10.2c-12.355-8.78-66.045-62.646-70.8-110.1,40.388,85.426,79.111,96.1,107.62,129.325V340.2h24.707v-8.131c28.508-33.221,67.233-43.9,107.619-129.325-4.75,47.459-58.442,101.325-70.8,110.1l9.976,10.2c19.006-19.458,85.526-73.56,85.526-73.56L430.249,365.525V450s27.8-40.815,34.923-60.984v-28.95l-17.343,28.475ZM392,313.083c-17.818-11.865-63.668-39.629-82.672-83.053a314.117,314.117,0,0,0,34.447,34.882s-1.189-30.61,1.186-37.255c4.276,36.781,13.068,52.442,47.039,71.9,33.973-19.458,42.763-35.119,47.039-71.9,2.375,6.645,1.188,37.255,1.188,37.255a314.117,314.117,0,0,0,34.447-34.882C455.668,273.454,409.818,301.218,392,313.083Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
6
public/img/heimdall-logo-small.svg
Normal file
6
public/img/heimdall-logo-small.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16pt" height="16pt" viewBox="0 0 16 16" version="1.1">
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 9.777344 14.660156 L 9.777344 13.738281 L 10.09375 12.761719 C 12.300781 10.574219 14.035156 8.527344 14.339844 7.894531 L 13.964844 8.027344 C 13.964844 8.027344 14.316406 7.589844 14.28125 7.34375 C 14 3.058594 11.582031 0.824219 10.917969 0.277344 C 11.898438 1.453125 11.628906 1.839844 11.628906 1.839844 C 11.195312 1.035156 10.308594 0.253906 10.132812 0.0546875 L 9.925781 1.304688 C 10.765625 1.792969 10.542969 2.074219 10.542969 2.074219 C 10.34375 1.792969 9.808594 1.546875 9.808594 1.546875 L 9.75 1.898438 C 10.003906 2.015625 11.160156 2.714844 11.171875 4.511719 C 11.171875 6.699219 9.925781 7.277344 9.707031 7.363281 C 8.980469 6.925781 8.191406 6.933594 8 6.917969 C 7.808594 6.933594 7.019531 6.925781 6.292969 7.363281 C 6.074219 7.273438 4.828125 6.699219 4.828125 4.511719 C 4.839844 2.714844 5.996094 2.015625 6.25 1.898438 L 6.191406 1.546875 C 6.191406 1.546875 5.65625 1.792969 5.457031 2.074219 C 5.457031 2.074219 5.234375 1.792969 6.074219 1.304688 L 5.867188 0.0546875 C 5.691406 0.253906 4.804688 1.035156 4.371094 1.839844 C 4.371094 1.839844 4.101562 1.453125 5.082031 0.277344 C 4.417969 0.824219 2 3.058594 1.71875 7.34375 C 1.683594 7.589844 2.035156 8.027344 2.035156 8.027344 L 1.660156 7.894531 C 1.964844 8.527344 3.699219 10.574219 5.90625 12.761719 L 6.222656 13.738281 L 6.222656 14.660156 L 5.941406 13.679688 L 5.300781 12.628906 L 5.300781 13.695312 C 5.566406 14.441406 6.589844 15.945312 6.589844 15.945312 L 6.589844 12.832031 L 2.667969 8.550781 C 2.667969 8.550781 5.117188 10.546875 5.820312 11.265625 L 6.1875 10.886719 C 5.730469 10.566406 3.753906 8.578125 3.578125 6.828125 C 5.066406 9.980469 6.492188 10.371094 7.542969 11.597656 L 7.542969 11.898438 L 8.457031 11.898438 L 8.457031 11.597656 C 9.507812 10.371094 10.933594 9.980469 12.421875 6.828125 C 12.246094 8.578125 10.269531 10.566406 9.8125 10.886719 L 10.179688 11.265625 C 10.882812 10.546875 13.332031 8.550781 13.332031 8.550781 L 9.410156 12.832031 L 9.410156 15.945312 C 9.410156 15.945312 10.433594 14.441406 10.699219 13.695312 L 10.699219 12.628906 L 10.058594 13.679688 Z M 8 10.898438 C 7.34375 10.460938 5.652344 9.4375 4.953125 7.835938 C 5.339844 8.296875 5.765625 8.726562 6.222656 9.121094 C 6.222656 9.121094 6.179688 7.992188 6.265625 7.746094 C 6.421875 9.105469 6.746094 9.679688 8 10.398438 C 9.253906 9.679688 9.578125 9.105469 9.734375 7.746094 C 9.820312 7.992188 9.777344 9.121094 9.777344 9.121094 C 10.234375 8.726562 10.660156 8.296875 11.046875 7.835938 C 10.347656 9.4375 8.65625 10.460938 8 10.898438 Z M 8 10.898438 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
11
public/img/heimdall-logo-square.svg
Normal file
11
public/img/heimdall-logo-square.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="434" height="434" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g>
|
||||
<title>background</title>
|
||||
<rect fill="none" id="canvas_background" height="436" width="436" y="-1" x="-1"/>
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<path id="svg_1" d="m265.227,397.619l0,-24.919l8.552,-26.577c59.868,-59.323 106.907,-114.847 115.221,-131.932l-10.215,3.56s9.5,-11.864 8.552,-18.51c-7.6,-116.273 -73.17,-176.862 -91.226,-191.732c26.607,31.955 19.326,42.4 19.326,42.4c-11.723,-21.833 -35.797,-43.032 -40.549,-48.409l-5.7,33.853c22.806,13.289 16.79,20.882 16.79,20.882c-5.387,-7.594 -19.957,-14.235 -19.957,-14.235l-1.586,9.491c6.973,3.165 38.327,22.149 38.565,70.872c0,59.323 -33.735,74.985 -39.674,77.357c-19.718,-11.865 -41.1,-11.627 -46.326,-12.1c-5.226,0.474 -26.608,0.236 -46.324,12.1c-5.941,-2.376 -39.676,-18.038 -39.676,-77.361c0.238,-48.723 31.6,-67.707 38.564,-70.872l-1.581,-9.487s-14.574,6.644 -19.955,14.238c0,0 -6.022,-7.593 16.786,-20.882l-5.702,-33.856c-4.752,5.378 -28.824,26.577 -40.543,48.407c0,0 -7.288,-10.443 19.32,-42.4c-18.054,14.87 -83.625,75.459 -91.226,191.732c-0.95,6.646 8.554,18.51 8.554,18.51l-10.217,-3.558c8.316,17.085 55.355,72.612 115.221,131.935l8.554,26.577l0,24.916l-7.6,-26.577l-17.345,-28.475l0,28.95c7.127,20.169 34.921,60.983 34.921,60.983l0,-84.475l-106.431,-116.037s66.52,54.1 85.526,73.56l9.978,-10.2c-12.355,-8.78 -66.045,-62.646 -70.8,-110.1c40.388,85.426 79.111,96.1 107.62,129.325l0,8.127l24.707,0l0,-8.131c28.508,-33.221 67.233,-43.9 107.619,-129.325c-4.75,47.459 -58.442,101.325 -70.8,110.1l9.976,10.2c19.006,-19.458 85.526,-73.56 85.526,-73.56l-106.423,116.041l0,84.475s27.8,-40.815 34.923,-60.984l0,-28.95l-17.343,28.475l-7.602,26.578zm-48.227,-102.036c-17.818,-11.865 -63.668,-39.629 -82.672,-83.053a314.117,314.117 0 0 0 34.447,34.882s-1.189,-30.61 1.186,-37.255c4.276,36.781 13.068,52.442 47.039,71.9c33.973,-19.458 42.763,-35.119 47.039,-71.9c2.375,6.645 1.188,37.255 1.188,37.255a314.117,314.117 0 0 0 34.447,-34.882c-19.006,43.424 -64.856,71.188 -82.674,83.053z" class="cls-1"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
11
public/img/heimdall-logo.svg
Normal file
11
public/img/heimdall-logo.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="346" height="434" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g>
|
||||
<title>background</title>
|
||||
<rect fill="none" id="canvas_background" height="436" width="348" y="-1" x="-1"/>
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<path id="svg_1" d="m221.227,397.119l0,-24.919l8.552,-26.577c59.868,-59.323 106.907,-114.847 115.221,-131.932l-10.215,3.56s9.5,-11.864 8.552,-18.51c-7.6,-116.273 -73.17,-176.862 -91.226,-191.732c26.607,31.955 19.326,42.4 19.326,42.4c-11.723,-21.833 -35.797,-43.032 -40.549,-48.409l-5.7,33.853c22.806,13.289 16.79,20.882 16.79,20.882c-5.387,-7.594 -19.957,-14.235 -19.957,-14.235l-1.586,9.491c6.973,3.165 38.327,22.149 38.565,70.872c0,59.323 -33.735,74.985 -39.674,77.357c-19.718,-11.865 -41.1,-11.627 -46.326,-12.1c-5.226,0.474 -26.608,0.236 -46.324,12.1c-5.941,-2.376 -39.676,-18.038 -39.676,-77.361c0.238,-48.723 31.6,-67.707 38.564,-70.872l-1.581,-9.487s-14.574,6.644 -19.955,14.238c0,0 -6.022,-7.593 16.786,-20.882l-5.702,-33.856c-4.752,5.378 -28.824,26.577 -40.543,48.407c0,0 -7.288,-10.443 19.32,-42.4c-18.054,14.87 -83.625,75.459 -91.226,191.732c-0.95,6.646 8.554,18.51 8.554,18.51l-10.217,-3.558c8.316,17.085 55.355,72.612 115.221,131.935l8.554,26.577l0,24.916l-7.6,-26.577l-17.345,-28.475l0,28.95c7.127,20.169 34.921,60.983 34.921,60.983l0,-84.475l-106.431,-116.037s66.52,54.1 85.526,73.56l9.978,-10.2c-12.355,-8.78 -66.045,-62.646 -70.8,-110.1c40.388,85.426 79.111,96.1 107.62,129.325l0,8.127l24.707,0l0,-8.131c28.508,-33.221 67.233,-43.9 107.619,-129.325c-4.75,47.459 -58.442,101.325 -70.8,110.1l9.976,10.2c19.006,-19.458 85.526,-73.56 85.526,-73.56l-106.423,116.041l0,84.475s27.8,-40.815 34.923,-60.984l0,-28.95l-17.343,28.475l-7.602,26.578zm-48.227,-102.036c-17.818,-11.865 -63.668,-39.629 -82.672,-83.053a314.117,314.117 0 0 0 34.447,34.882s-1.189,-30.61 1.186,-37.255c4.276,36.781 13.068,52.442 47.039,71.9c33.973,-19.458 42.763,-35.119 47.039,-71.9c2.375,6.645 1.188,37.255 1.188,37.255a314.117,314.117 0 0 0 34.447,-34.882c-19.006,43.424 -64.856,71.188 -82.674,83.053z" class="cls-1"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -1,171 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 712 712"
|
||||
height="712"
|
||||
width="712"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath18"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path16"
|
||||
d="M 0,534 H 534 V 0 H 0 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,712)"
|
||||
id="g10"><g
|
||||
id="g12"><g
|
||||
clip-path="url(#clipPath18)"
|
||||
id="g14"><g
|
||||
transform="translate(393.811,345.8316)"
|
||||
id="g20"><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 24.538,-48.679 35.693,-96.638 39.077,-128.853 3.409,2.889 6.518,5.987 9.318,9.295 C 44.008,-86.276 33.201,-45.41 13.482,-2.216 9.21,-1.054 4.714,-0.293 0,0" /></g><g
|
||||
transform="translate(474.0073,283.56)"
|
||||
id="g24"><path
|
||||
id="path26"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -2.746,20.364 -15.533,43.515 -36.693,60.311 0.831,-5.932 1.399,-11.795 1.735,-17.511 13.776,-14.605 22.245,-33.379 24.23,-48.275 4.005,-30.045 0.821,-64.541 -16.17,-93.955 -0.57,-8.119 -1.935,-15.947 -4.08,-23.411 C 0.994,-86.018 5.717,-42.414 0,0" /></g><g
|
||||
transform="translate(385.5994,134.225)"
|
||||
id="g28"><path
|
||||
id="path30"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 4.978,2.231 10.126,4.9 15.408,8.084 0.431,0.963 0.862,1.934 1.291,2.917 13.266,30.416 21.331,57.602 26.214,83.512 -1.261,8.494 -3.199,19.129 -6.164,31.354 C 33.096,92.579 25.043,59.43 8.133,18.154 5.496,11.715 2.793,5.672 0,0" /></g><g
|
||||
transform="translate(425.0383,307.4895)"
|
||||
id="g32"><path
|
||||
id="path34"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 3.757,-10.543 6.88,-20.55 9.476,-29.923 0.875,13.491 1.202,26.977 1.298,40.761 0.113,16.457 -1.829,35.048 -6.805,53.19 -4.505,3.565 -9.316,6.328 -14.259,8.445 C -2.33,50.589 0.215,26.875 0.073,6.612 0.058,4.391 0.033,2.189 0,0" /></g><g
|
||||
transform="translate(386.608,388.9227)"
|
||||
id="g36"><path
|
||||
id="path38"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 28.927,-1.359 56.121,-14.859 67.722,-50.801 1.163,-3.607 2.212,-7.125 3.152,-10.559 8.947,-11.458 15.298,-24.325 18.197,-37.212 -0.856,16.01 -4.261,34.252 -10.972,55.045 C 63.415,1.968 23.976,16.608 -13.505,19.408 -8.758,13.225 -4.247,6.745 0,0" /></g><g
|
||||
transform="translate(458.4243,221.6535)"
|
||||
id="g40"><path
|
||||
id="path42"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 C 3.127,14.302 3.772,27.883 3.416,39.047 -1.905,14.006 -15.995,-2.15 -31.262,-12.59 -32.789,-18.805 -34.49,-25.02 -36.37,-31.246 -23.389,-24.415 -10.119,-14.479 0,0" /></g><g
|
||||
transform="translate(444.3687,202.0113)"
|
||||
id="g44"><path
|
||||
id="path46"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -3.23,-2.766 -6.676,-5.371 -10.334,-7.809 -0.733,-41.782 -19.658,-69.771 -47.398,-84.823 -3.677,-5.665 -7.502,-10.841 -11.493,-15.546 41.029,14.834 69.423,50.013 69.423,99.046 C 0.198,-6.198 0.132,-3.151 0,0" /></g><g
|
||||
transform="translate(380.6335,369.7762)"
|
||||
id="g48"><path
|
||||
id="path50"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 5.226,-0.534 10.259,-1.404 15.092,-2.571 -0.889,1.692 -1.785,3.386 -2.702,5.082 -16.462,30.478 -37.594,55.26 -59.872,72.957 -3.747,0.455 -7.437,0.691 -11.034,0.691 -3.084,0 -6.086,-0.173 -9.012,-0.499 C -43.567,59.067 -19.689,32.831 0,0" /></g><g
|
||||
transform="translate(277.8203,439.6349)"
|
||||
id="g52"><path
|
||||
id="path54"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0.965,-0.781 1.902,-1.539 2.823,-2.285 16.915,10.338 37.922,14.465 62.771,9.042 28.083,-6.127 45.11,-20.81 57.944,-39.781 5.759,-1.525 11.199,-3.389 16.31,-5.591 C 126.46,-12.621 104.529,8.859 70.436,16.304 39.851,22.984 13.775,18.552 -7.75,5.74 -5.097,3.943 -2.508,2.031 0,0" /></g><g
|
||||
transform="translate(196.3198,437.5024)"
|
||||
id="g56"><path
|
||||
id="path58"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 4.283,-1.538 8.723,-3.338 13.331,-5.409 3.968,10.138 11.867,19.559 25.463,27.044 16.093,8.861 35.757,7.742 56.297,-1.356 5.767,1.684 11.725,2.851 17.868,3.497 C 85.335,39.045 57.854,43.048 36.898,33.259 18.38,24.608 6.825,12.856 0,0" /></g><g
|
||||
transform="translate(247.7137,105.3549)"
|
||||
id="g60"><path
|
||||
id="path62"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 C 6.127,1.673 11.893,3.458 17.327,5.333 4.444,12.581 -1.899,21.662 -3.581,31.408 c -0.604,3.504 -1.017,6.799 -0.093,10.712 0.924,3.914 6.739,8.375 9.302,5.407 2.8,-3.245 6.252,-6.183 9.475,-9.292 5.605,1.941 10.678,4.036 15.212,6.206 -3.849,6.266 -7.404,14.138 -6.947,20.42 0.458,6.281 3.075,10.52 8.603,12.187 11.415,3.442 21.999,2.374 25.566,-2.256 2.274,-2.952 2.84,-5.099 0.929,-12.432 C 56.556,55.027 28.877,37.837 -0.53,30.686 0.296,26.898 1.9,23.354 4.268,20.071 31.3,26.585 52.436,37.346 62.531,45.233 c 0,0 3.625,2.818 6.895,4.926 3.271,2.108 6.909,2.389 10.183,1.996 2.641,-0.469 5.128,-1.09 5.926,-3.136 0.424,-1.081 0.58,-2.506 0.793,-3.786 3.81,3.469 7.224,6.844 10.35,10.045 -0.094,0.709 -0.301,1.34 -0.592,3.327 -0.29,1.986 0.873,7.627 4.257,8.472 5.232,1.305 5.352,-2.019 4.758,-4.156 -0.324,-1.158 -2.535,-4.692 -4.491,-7.683 C 96.402,50.874 91.665,46.12 86.1,41.202 79.368,35.304 71.4,29.176 61.657,23.216 67.141,21.2 73.061,19.772 79.275,18.989 c 6.527,4.161 12.301,8.341 17.47,12.437 -0.006,0.015 -0.01,0.029 -0.015,0.045 15.64,12.39 32.343,29.791 34.477,31.837 2.133,2.048 4.192,3.572 9.673,6.772 5.481,3.198 8.032,3.11 12.757,5.157 2.108,6.12 4.032,12.142 5.782,18.099 -13.375,-4.56 -29.007,-6.117 -37.442,-2.982 -8.435,3.137 -9.809,6.612 -13.31,13.049 -6.778,12.464 -6.896,19.112 -13.912,22.317 -7.016,3.205 -22.831,5.462 -27.349,26.236 -4.519,20.774 -1.427,42.142 4.4,49.621 5.826,7.479 7.853,9.191 14.506,12.228 20.81,9.496 20.869,17.035 27.052,22.139 0.95,0.785 1.723,1.526 2.445,2.235 3.051,2.423 6.572,4.287 11.289,5.066 17.824,2.947 33.125,-0.539 45.766,-7.644 -0.524,4.921 -1.222,9.904 -2.118,14.903 -20.171,10.031 -45.318,14.571 -74.683,9.124 -8.344,-1.548 -13.881,-4.571 -21.833,-7.494 -7.954,-2.923 -17.15,1.224 -10.273,9.394 1.746,2.073 3.381,4.053 6.551,5.841 3.17,1.786 5.376,2.748 8.251,4.031 11.585,5.172 25.064,9.265 38.919,11.15 -5.214,7.342 -10.657,14.284 -16.279,20.766 -9.394,-0.39 -20.213,-1.851 -26.032,-2.44 -5.82,-0.589 -9.06,1.857 -12.536,3.822 -7.924,5.899 -18.154,14.12 -34.522,27.37 -11.615,9.402 -24.85,16.142 -38.12,19.963 -0.474,-0.24 -0.945,-0.486 -1.41,-0.743 -5.039,-2.774 -9.226,-5.808 -12.69,-9.025 14.703,-2.765 30.868,-9.573 44.139,-20.356 13.952,-11.337 18.206,-24.704 19.888,-36.34 0.168,-1.155 0.266,-1.815 0.311,-3.475 0.047,-1.659 -0.815,-3.004 -1.678,-3.707 -2.718,-2.211 -8.249,3.916 -13.274,6.929 -2.904,2.223 -5.982,4.456 -9.319,6.723 -3.764,2.558 -7.468,5.013 -11.113,7.371 -3.931,-6.369 -7.327,-13.324 -10.143,-20.75 3.692,-5.018 7.901,-11.893 9.644,-16.1 1.743,-4.206 1.807,-7.837 0.673,-10.29 -1.401,-3.03 -5.825,-9.296 -13.094,-7.378 -7.269,1.917 -6.375,9.465 -5.584,15.816 5.308,23.027 15.847,44.264 31.304,59.454 -3.615,2.885 -7.555,5.533 -11.704,7.903 -14.439,-12.917 -26.266,-30.211 -35.458,-50.71 -0.19,-0.422 -0.226,-0.513 -0.565,-1.268 -0.803,-1.788 -2.853,-1.544 -3.596,0.022 -0.282,0.594 -0.385,0.847 -0.574,1.275 -4.022,9.093 -6.995,19.365 -7.268,29.685 -5.63,3.508 -11.066,6.374 -16.297,8.602 -2.454,-10.066 -2.772,-20.285 -1.894,-29.82 0.158,-1.716 0.303,-2.252 0.534,-3.917 0.028,-0.267 0.402,-1.515 -0.223,-1.559 -0.349,-0.025 -1.27,1.562 -1.427,1.781 -1.017,1.66 -1.304,2.068 -2.525,3.581 -5.657,7.005 -13.679,12.164 -25.732,13.032 -10.722,0.773 -22.284,-0.972 -33.613,-5.296 -2.457,-4.819 -4.631,-10.233 -6.51,-16.211 10.888,5.567 22.052,7.726 31.726,6.586 25.225,-2.974 25.025,-18.049 24.213,-22.17 -0.49,-2.493 -2.607,-2.523 -4.95,-2.523 -2.478,0 -5.264,0.014 -7.874,0.032 -7.606,0.617 -15.399,0.53 -23.172,-0.401 -1.869,-4.868 -3.708,-9.939 -5.517,-15.209 16.143,1.05 29.297,-4.241 36.802,-6.503 21.998,-6.629 31.101,-15.861 39.409,-27.368 5.162,-12.231 7.725,-25.405 9.58,-34.362 2.854,-13.771 1.696,-21.754 -2.14,-27.304 -6.633,-9.598 -13.332,-27.17 -18.702,-30.879 -8.576,-5.921 -26.334,-7.643 -31.417,-12.986 -5.308,-5.578 -7.448,-9.838 -11.965,-11.274 -2.401,-0.765 -4.292,-1.24 -7.298,-1.902 -12.923,-2.85 -28.529,1.171 -42.374,11.419 0.076,-5.029 0.323,-9.919 0.744,-14.666 17.101,-12.923 35.852,-19.863 50.79,-19.313 1.187,0.044 1.919,0.102 3.485,0.275 2.069,0.226 3.367,-1.034 3.862,-2.492 0.496,-1.459 1.041,-2.852 1.607,-4.341 3.641,-9.571 8.553,-20.824 14.704,-32.399 6.483,-0.835 13.109,-1.292 19.835,-1.367 -6.27,17.703 -7.737,34.454 -3.319,43.508 1.211,2.483 3.294,4.888 4.982,5.574 1.69,0.684 3.057,1.633 7.932,1.99 4.875,0.356 10.428,-0.861 10.357,-3.487 -0.072,-2.627 -1.118,-4.924 -1.498,-6.722 C -35.786,37.896 -28.37,15.753 0,0" /></g><g
|
||||
transform="translate(345.0594,86.9108)"
|
||||
id="g64"><path
|
||||
id="path66"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 C 4.957,3.508 9.604,7.594 13.989,12.282 -4.084,8.229 -24.025,8.156 -44.19,11.921 c -4.428,0.826 -8.556,1.754 -12.399,2.773 -5.437,-2.183 -11.057,-4.241 -16.871,-6.18 8.45,-2.639 17.983,-4.917 28.679,-6.836 C -29.302,-1.096 -14.22,-1.59 0,0" /></g><g
|
||||
transform="translate(424.0582,155.6551)"
|
||||
id="g68"><path
|
||||
id="path70"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -3.333,-3.006 -6.899,-5.889 -10.721,-8.629 -23.418,-16.791 -47.229,-24.75 -68.498,-26.057 -0.971,-3.554 -2.151,-7.019 -3.538,-10.38 21.907,0.434 46.121,6.788 69.041,21.707 C -7.959,-16.431 -3.382,-8.632 0,0" /></g><g
|
||||
transform="translate(332.0492,98.9441)"
|
||||
id="g72"><path
|
||||
id="path74"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 C 6.576,10.274 10.671,21.912 12.373,34.232 8.62,31.327 4.554,28.382 0.121,25.429 -2.374,16.757 -6.639,8.164 -12.496,0.352 -9.009,0.108 -5.545,-0.017 -2.119,-0.017 -1.411,-0.017 -0.705,-0.011 0,0" /></g><g
|
||||
transform="translate(293.4784,133.4932)"
|
||||
id="g76"><path
|
||||
id="path78"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -1.02,0.698 -2.019,1.44 -2.995,2.217 -3.934,-1.832 -8.175,-3.623 -12.68,-5.326 2.128,-1.663 4.345,-3.298 6.683,-4.897 10.13,-6.931 23.823,-11.988 39.452,-13.986 1.715,3.24 3.152,6.525 4.318,9.818 C 21.313,-10.722 9.406,-6.434 0,0" /></g><g
|
||||
transform="translate(373.0792,112.3586)"
|
||||
id="g80"><path
|
||||
id="path82"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -17.337,-25.704 -38.736,-39.907 -68.98,-43.872 -7.734,-4.602 -16.59,-8.148 -27.68,-10.426 52.785,-1.992 86.015,15.599 111.917,59.48 C 10.021,3.046 4.915,1.346 0,0" /></g><g
|
||||
transform="translate(207.2643,116.8778)"
|
||||
id="g84"><path
|
||||
id="path86"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -0.838,-0.011 -1.675,-0.017 -2.51,-0.017 h -0.006 c -4.847,0 -9.642,0.188 -14.384,0.548 11.348,-17.77 25.585,-34.706 42.6,-45.874 6.415,-1.663 12.827,-2.52 19.16,-2.52 2.66,0 5.293,0.122 7.891,0.354 C 29.652,-42.081 11.377,-21.927 0,0" /></g><g
|
||||
transform="translate(225.2887,402.3531)"
|
||||
id="g88"><path
|
||||
id="path90"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 C 2.856,4.852 5.877,9.429 9.057,13.724 -9.122,24.262 -25.618,31.778 -40.359,35.77 -43.291,33.619 -46.769,30.646 -50.677,26.393 -37.61,24.056 -22.788,17.057 -6.339,4.976 -4.139,3.36 -2.028,1.701 0,0" /></g><g
|
||||
transform="translate(153.844,407.1487)"
|
||||
id="g92"><path
|
||||
id="path94"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0.586,0 1.172,-0.01 1.757,-0.024 15.837,27.113 28.961,34.536 34.736,37.816 2.637,1.498 5.828,2.582 9.427,3.257 0.096,0.128 0.189,0.257 0.285,0.384 3.462,4.529 7.526,8.693 12.156,12.478 -7.686,-0.075 -15,-1.294 -21.582,-3.718 C 27.323,46.71 9.311,35.291 -10.369,-0.704 -6.903,-0.239 -3.442,0 0,0" /></g><g
|
||||
transform="translate(110.5027,359.7524)"
|
||||
id="g96"><path
|
||||
id="path98"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 6.233,38.52 20.951,62.47 43.115,68.417 3.7,5.186 7.278,9.552 10.669,13.232 C 19.274,82.625 -2.578,56.901 -10.403,-5.079 -7.057,-3.186 -3.586,-1.493 0,0" /></g><g
|
||||
transform="translate(142.7769,130.788)"
|
||||
id="g100"><path
|
||||
id="path102"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 6.02,-9.512 12.474,-18.353 19.267,-26.357 5.732,-2.097 11.846,-3.64 18.317,-4.625 -7.65,7.45 -15.05,16.112 -22.015,25.948 23.025,-6.224 45.696,-7.137 66.372,-5.01 C 79.408,-6.74 77.314,-3.221 75.652,0.533 53.659,-1.389 29.867,0.362 7.016,8.019 c -6.702,11.042 -12.871,23.29 -18.309,36.72 -4.76,1.763 -9.576,4.013 -14.349,6.705 5.008,-13.053 10.815,-25.558 17.267,-37.269 -4.59,2.155 -9.114,4.579 -13.548,7.298 -30.386,18.628 -45.7,47.92 -50.912,77.884 -4.917,8.92 -9.269,19.492 -11.863,31.644 C -86.618,88.432 -72.512,40.94 -28.732,14.102 -19.237,8.28 -9.621,3.637 0,0" /></g><g
|
||||
transform="translate(88.5718,224.2917)"
|
||||
id="g104"><path
|
||||
id="path106"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -11.332,15.213 -19.117,36.192 -19.117,62.341 0,37.856 12.897,64.906 29.809,81.738 1.148,6.561 2.496,12.714 4.041,18.436 -25.112,-18.504 -44.885,-51.876 -44.885,-101.002 0,-30.917 12.513,-57.099 29.663,-76.362 C -0.476,-10.007 -0.313,-5.056 0,0" /></g><g
|
||||
transform="translate(132.9481,385.021)"
|
||||
id="g108"><path
|
||||
id="path110"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -7.698,-17.341 -15.463,-38.736 -22.904,-65.126 -0.223,-11.817 0.107,-24.437 0.996,-37.732 0.021,-0.315 0.045,-0.626 0.066,-0.942 11.167,47.936 22.9,81.62 33.897,105.42 C 8.138,1.593 4.085,1.045 0,0" /></g><g
|
||||
transform="translate(80.9783,335.1565)"
|
||||
id="g112"><path
|
||||
id="path114"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -5.227,-12.952 -8.107,-27.538 -8.593,-43.587 5.086,19.742 14.002,35.727 24.537,43.499 6.063,4.47 12.004,7.641 17.74,9.824 1.715,5.241 3.468,10.334 5.256,15.261 C 28.354,21.684 18.126,16.53 8.81,9.171 5.747,6.751 2.792,3.66 0,0" /></g><g
|
||||
transform="translate(107.5541,165.6139)"
|
||||
id="g116"><path
|
||||
id="path118"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 C -4.269,15.889 -6.1,34.231 -5.276,54.798 -8.364,67.6 -10.59,80.395 -11.941,93.107 -17.06,64.013 -17.85,38.438 -14.934,16.468 -10.781,10.732 -5.851,5.174 0,0" /></g><g
|
||||
transform="translate(305.6711,84.8346)"
|
||||
id="g120"><path
|
||||
id="path122"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -13.748,-11.22 -33.729,-18.651 -55.357,-18.651 -14.953,0 -31.093,5.166 -46.959,15.248 -1.537,-0.047 -3.066,-0.073 -4.581,-0.073 h -0.005 c -4.859,0 -9.596,0.238 -14.205,0.709 18.555,-15.209 38.58,-24.093 58.523,-24.093 39.332,0 53.602,7.14 75.98,25.488 C 8.953,-1.1 4.479,-0.641 0,0" /></g><g
|
||||
transform="translate(212.4133,84.8215)"
|
||||
id="g124"><path
|
||||
id="path126"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -3.35,3.361 -6.644,6.999 -9.876,10.909 -20.874,-0.646 -38.945,3.341 -53.773,11.661 -12.673,7.46 -22.973,18.151 -30.64,31.794 -1.872,1.057 -3.73,2.147 -5.572,3.277 -4.478,2.744 -8.708,5.733 -12.69,8.958 3.258,-9.117 7.365,-17.325 12.241,-24.613 h -0.046 C -79.294,10.472 -43.813,-3.836 0,0" /></g><g
|
||||
transform="translate(304.2728,112.9123)"
|
||||
id="g128"><path
|
||||
id="path130"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -0.277,0.089 -0.554,0.177 -0.829,0.269 -0.536,0.175 -1.068,0.354 -1.597,0.54 -0.153,0.053 -0.303,0.109 -0.456,0.163 -0.495,0.177 -0.991,0.354 -1.481,0.538 -0.132,0.049 -0.262,0.102 -0.395,0.152 -0.507,0.193 -1.013,0.387 -1.513,0.588 -0.111,0.045 -0.221,0.092 -0.331,0.136 -0.519,0.21 -1.035,0.423 -1.544,0.641 -0.097,0.041 -0.19,0.082 -0.285,0.125 -0.522,0.225 -1.041,0.454 -1.554,0.686 -0.087,0.04 -0.173,0.081 -0.26,0.122 -0.517,0.238 -1.029,0.477 -1.537,0.725 -0.088,0.042 -0.175,0.087 -0.264,0.13 -0.526,0.258 -1.048,0.518 -1.565,0.785 -14.874,-7.004 -32.975,-13.4 -55.354,-18.43 -4.137,-0.93 -8.191,-1.706 -12.166,-2.341 0.2,-0.244 0.401,-0.481 0.602,-0.722 -0.004,-10e-4 -0.006,-0.002 -0.01,-0.003 2.814,-3.38 5.746,-6.459 8.773,-9.22 0.008,0.001 0.016,0.003 0.024,0.005 0.016,-0.015 0.032,-0.03 0.047,-0.043 2.277,0.457 4.569,0.955 6.882,1.502 27.268,6.448 48.885,14.524 66.35,23.169 C 1.02,-0.327 0.51,-0.164 0,0" /></g><g
|
||||
transform="translate(98.6179,332.7756)"
|
||||
id="g132"><path
|
||||
id="path134"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -0.211,-0.155 -0.42,-0.322 -0.63,-0.484 -0.959,-14.52 -1.313,-30.63 -1.05,-48.42 0.373,-25.232 4.421,-50.661 11.294,-74.894 4.558,-3.189 9.331,-5.712 14.138,-7.502 C 16.559,-107.411 11.56,-80.535 9.573,-50.802 8.177,-29.897 8.153,-10.905 9.438,5.971 6.236,4.268 3.087,2.276 0,0" /></g></g></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 18 KiB |
833
public/js/app.js
vendored
833
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
2482
public/js/fontawesome.js
vendored
Normal file
2482
public/js/fontawesome.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/jquery-3.3.1.min.js
vendored
2
public/js/jquery-3.3.1.min.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/jquery-3.6.0.min.js
vendored
Normal file
2
public/js/jquery-3.6.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
13
public/js/jquery-ui.min.js
vendored
Normal file
13
public/js/jquery-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/select2.min.js
vendored
Normal file
1
public/js/select2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/manifest.json
generated
2
public/manifest.json
generated
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "App",
|
||||
"name": "Heimdall",
|
||||
"icons": [
|
||||
{
|
||||
"src": "\/android-icon-36x36.png",
|
||||
|
||||
6
public/mix-manifest.json
generated
6
public/mix-manifest.json
generated
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"/css/app.css": "/css/app.css?id=414b5bf109854d80b269",
|
||||
"/js/app.js": "/js/app.js?id=b38be2e595ece6fcef81"
|
||||
}
|
||||
"/css/app.css": "/css/app.css?id=bc18c3a0e8475fe00a5a",
|
||||
"/js/app.js": "/js/app.js?id=c95edea425171c6ce8f6"
|
||||
}
|
||||
|
||||
170
readme.md
170
readme.md
@@ -1,46 +1,85 @@
|
||||

|
||||
# Heimdall
|
||||
|
||||
## About
|
||||
Heimdall is a way to organise all those links to your most used web sites and web applications in a simple way.
|
||||
[](https://heimdall.site)
|
||||
|
||||
Simplicity is the key to Heimdall.
|
||||
[](https://discord.gg/CCjHKn4)
|
||||
[](https://hub.docker.com/r/linuxserver/heimdall/)
|
||||
[](https://www.firsttimersonly.com/)
|
||||
[](https://www.paypal.me/heimdall)
|
||||
|
||||
Why not use it as your browser start page? It even has the ability to include a search bar using either Google, Bing or DuckDuckGo.
|
||||
___
|
||||
|
||||

|
||||
Visit the website - https://heimdall.site
|
||||
___
|
||||
|
||||
## About
|
||||
As the name suggests Heimdall Application Dashboard is a dashboard for all your web applications. It doesn't need to be limited to applications though, you can add links to anything you like.
|
||||
|
||||
Heimdall is an elegant solution to organise all your web applications. It’s dedicated to this purpose so you won’t lose your links in a sea of bookmarks.
|
||||
|
||||
Why not use it as your browser start page? It even has the ability to include a search bar using either Google, Bing or DuckDuckGo.
|
||||
|
||||

|
||||
|
||||
## Video
|
||||
If you want to see a quick video of it in use, go to https://drive.google.com/file/d/1cijXgmjem_q2OfKMp36qVuXRiyOzvhWC/view
|
||||
If you want to see a quick video of it in use, go to https://youtu.be/GXnnMAxPzMc
|
||||
|
||||
## Supported applications
|
||||
You can use the app to link to any site or application, but "Supported" apps will auto fill in the icon for the app and supply a default color for the tile. In addition *enhanced apps allow you provide details to an apps API, allowing you to view live stats directly on the dashboad. For example, the NZBGet and Sabnzbd Enhanced apps will display the queue size and download speed while something is downloading.
|
||||
You can use the app to link to any site or application, but Foundation apps will auto fill in the icon for the app and supply a default color for the tile. In addition Enhanced apps allow you provide details to an apps API, allowing you to view live stats directly on the dashboad. For example, the NZBGet and Sabnzbd Enhanced apps will display the queue size and download speed while something is downloading.
|
||||
|
||||
**Enhanced**
|
||||
- NZBGet
|
||||
- Sabnzbd
|
||||
Supported applications are recognized by the title of the application as entered in the title field when adding an application. For example, to add a link to pfSense, begin by typing "p" in the title field and then select "pfSense" from the list of supported applications.
|
||||
|
||||
**Supported**
|
||||
- Duplicati
|
||||
- Emby
|
||||
- NZBGet
|
||||
- pFsense
|
||||
- Pihole
|
||||
- Plex
|
||||
- Portainer
|
||||
- UniFi
|
||||
- Sabnzbd
|
||||
[](https://apps.heimdall.site/applications/enhanced)
|
||||
|
||||
[](https://apps.heimdall.site/applications/foundation)
|
||||
|
||||
## Installing
|
||||
Apart from the Laravel dependencies, namely PHP >= 7.0.0, OpenSSL PHP Extension, PDO PHP Extension, Mbstring PHP Extension, Tokenizer PHP Extension and XML PHP Extension, the only other thing Heimdall needs is sqlite support.
|
||||
Apart from the Laravel dependencies, namely PHP >= 7.2.5, BCMath PHP Extension, Ctype PHP Extension, Fileinfo PHP extension, JSON PHP Extension, Mbstring PHP Extension, OpenSSL PHP Extension, PDO PHP Extension, Tokenizer PHP Extension, XML PHP Extension, the only other thing Heimdall needs is sqlite support and zip support (php-zip).
|
||||
|
||||
Installation is as simple as cloning the repository somewhere, or downloading and extracting the zip/tar and pointing your httpd document root to it. For simple testing you could just go to the folder and type `php artisan serve`
|
||||
If you find you can't change the background make sure `php_fileinfo` is enabled in your php.ini. I believe it should be by default, but one user came across the issue on a windows system.
|
||||
|
||||
Installation is as simple as cloning the repository somewhere, or downloading and extracting the zip/tar and pointing your httpd document root to the `/public` folder then creating the .env file and generating an encryption key (this is all taken care of for you with the docker).
|
||||
|
||||
```
|
||||
cd /path/to/heimdall
|
||||
cp .env.example .env
|
||||
php artisan key:generate
|
||||
```
|
||||
|
||||
For simple testing you could just go to the folder and type `php artisan serve`
|
||||
|
||||
There is also a multi-arch Docker which supports x86-64, armhf and arm64, instructions on how to use them at
|
||||
|
||||
- https://hub.docker.com/r/linuxserver/heimdall/
|
||||
|
||||
## Updating
|
||||
To update your instance, simply clone this repository or download the zip/tar file with the new version and copy it over the old installation.
|
||||
|
||||
## Search Providers
|
||||
v2.3.0 added the ability for users to customise the search options.
|
||||
|
||||
Options are stored in `/storage/app/searchproviders.yaml` (`/config/www/searchproviders.yaml` on docker installs), feel free to rearrange the options, add new ones, delete ones you don't use, etc.
|
||||
|
||||
Consider contributing to https://github.com/linuxserver/Heimdall/discussions/categories/search-providers to help others add new ones.
|
||||
|
||||
The item at the top of the list `Tiles` allows you to search for apps on your dashboard by name, helpful when you have lots of icons.
|
||||
|
||||
## New background image not being set
|
||||
If you are using the docker image or a default php install you may find images over 2MB wont get set as the background image, you just need to change the `upload_max_filesize` in the php.ini.
|
||||
|
||||
If you are using the linuxserver.io docker image simply edit `/path/to/config/php/php-local.ini` and add `upload_max_filesize = 30M` to the end.
|
||||
|
||||
## Docker and enhanced apps
|
||||
If you are running the docker and the EnhancedApps you are using are also in dockers, you may need to use the docker networking addresses to communicate with them.
|
||||
|
||||
You can do this by using `http(s)://docker_name:port` in the config section. Instead of the name you can use the internal docker ip, this usually starts with `172.`
|
||||
|
||||
## Languages
|
||||
The app has been translated into several languages, however the quality of the translations could do with work, if you would like to improve them or help with other translations they are stored in /resources/lang/
|
||||
The app has been translated into several languages; however, the quality of the translations could do with work. If you would like to improve them, or help with other translations, they are stored in `/resources/lang/`.
|
||||
|
||||
To create a new one, create a new folder with the ISO 3166-1 alpha-2 code as the name, copy app.php from /resources/lang/en/app.php into your new folder and replace the english strings.
|
||||
To create a new language translation, make a new folder with the ISO 3166-1 alpha-2 code as the name, copy `app.php` from `/resources/lang/en/app.php` into your new folder and replace the English strings.
|
||||
|
||||
When you are finished create a pull request.
|
||||
When you are finished, create a pull request.
|
||||
|
||||
Currently added languages are
|
||||
|
||||
@@ -50,12 +89,26 @@ Currently added languages are
|
||||
- French
|
||||
- Swedish
|
||||
- Spanish
|
||||
- Turkish
|
||||
- Russian
|
||||
|
||||
## Web Server Configuration
|
||||
|
||||
### Apache
|
||||
A .htaccess file ships with the app, however, if it does not work with your Apache installation, try this alternative:
|
||||
A `.htaccess` file ships with the app, however, a lot of apache installations disallow `.htaccess` files by default.
|
||||
You will notice this due to some links not working like `/settings`.
|
||||
In addition mod-rewrite needs to be enabled if it isn't already.
|
||||
|
||||
#### Fixes & work around options
|
||||
##### - Apache global allow .htaccess
|
||||
Find the `AllowOverride None` line in your apache configuration and change this to `AllowOverride All`
|
||||
|
||||
##### - Apache vhost configuration allow .htaccess
|
||||
In the apache vhost configuration in the `<Directory />` block add `AllowOverride All`
|
||||
|
||||
##### - Add .htaccess content in apache configuration
|
||||
You can add the full `.htaccess` into your apache configuration, this way you do not need to allow `.htaccess` files.
|
||||
You can even shorten the content of the `.htaccess` when inserting it into the apache configuration to:
|
||||
```
|
||||
Options +FollowSymLinks
|
||||
RewriteEngine On
|
||||
@@ -64,30 +117,79 @@ RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
```
|
||||
#### More info
|
||||
More info about `AllowOverride` can be found here:
|
||||
https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride
|
||||
|
||||
|
||||
|
||||
### Nginx
|
||||
If you are using Nginx, the following directive in your site configuration will direct all requests to the index.php front controller:
|
||||
If you are using Nginx, the following directive in your site configuration will direct all requests to the `index.php` front controller:
|
||||
|
||||
```
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
```
|
||||
Someone was using the same nginx setup to both run this and reverse proxy Plex, Plex is served from /web so their location was interferring with the /webfonts.
|
||||
Someone was using the same nginx setup to both run this and reverse proxy Plex, Plex is served from `/web` so their location was interfering with the `/webfonts`.
|
||||
|
||||
Therefore, if your fonts aren't showing because you have a location for /web add the following
|
||||
Therefore, if your fonts aren't showing because you have a location for `/web`, add the following
|
||||
```
|
||||
location /webfonts {
|
||||
try_files $uri $uri/;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
```
|
||||
If there are any other locations which might interefere with any of the folders in the /public folder, you might have to do the same for those as well, but it's a super fringe case.
|
||||
If there are any other locations which might interfere with any of the folders in the `/public` folder, you might have to do the same for those as well, but it's a super fringe case.
|
||||
|
||||
### Reverse proxy
|
||||
If you'd like to reverse proxy this app, we recommend using our letsencrypt/nginx docker image: [SWAG - Secure Web Application Gateway](https://hub.docker.com/r/linuxserver/swag)
|
||||
You can either reverse proxy from the root location, or from a subdomain (subfolder method is currently not supported). For HTTPS proxy, make sure you use the HTTPS port of Heimdall webserver, otherwise some links may break. You can add security through `.htpasswd`
|
||||
|
||||
```
|
||||
location / {
|
||||
auth_basic "Restricted";
|
||||
auth_basic_user_file /config/nginx/.htpasswd;
|
||||
include /config/nginx/proxy.conf;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_pass http://heimdall;
|
||||
}
|
||||
```
|
||||
|
||||
### Self-signed certificates and local CAs
|
||||
Per default Heimdall uses the standard certificate bundle file (`ca-certificates.crt`) to verify HTTPS sites and will ignore additional certificates placed in `/etc/ssl/certs`. If you wish to use enhanced apps with HTTPS sites that use a self-signed certificate or certs signed with your own local CA, you can override the default bundle:
|
||||
|
||||
- Create a unified certificate `.pem` file that contains all CAs and certificates that Heimdall has to verify. For example, if you use both LetsEncrypt and a local CA for your internal apps, concatenate the LetsEncrypt intermediate CA (export via browser) and your local CA `cert.pem` (or any number of self-signed certs) into one `heimdall.pem` file.
|
||||
- Place the `heimdall.pem` into the container (if you use Docker), for example by placing it in the path that you mapped to `/config`. Make sure that the Heimdall user has read access (`chmod a+r`).
|
||||
- Set the `openssl.cafile` setting in `/config/php/php-local.ini` to your cert bundle:
|
||||
|
||||
```
|
||||
# /config/php/php-local.ini
|
||||
openssl.cafile = /config/heimdall.pem
|
||||
```
|
||||
|
||||
Restart the container and the enhanced apps should now be able to access your local HTTP websites. This configuration will survive updating or recreating the Heimdall container.
|
||||
|
||||
## Support
|
||||
https://discord.gg/CCjHKn4 or through GitHub issues
|
||||
|
||||
## Donate
|
||||
If you would like to show your appreciation, feel free to use the link below.
|
||||
|
||||
[](https://www.paypal.me/heimdall)
|
||||
|
||||
## Credits
|
||||
- PHP Framework - [Laravel](https://laravel.com/)
|
||||
- Icons - [FonteAwesome 5](https://fontawesome.com/)
|
||||
- Javascript - [jQuery](https://jquery.com/)
|
||||
- Icons - [FontAwesome 5](https://fontawesome.com/)
|
||||
- JavaScript - [jQuery](https://jquery.com/)
|
||||
- Colour picker - [Huebee](http://huebee.buzz/)
|
||||
- Background image - [pexels](https://www.pexels.com)
|
||||
- Everyone at Linuxserver.io that has helped with the app and let's not forget IronicBadger for the following question that started it all:
|
||||
```
|
||||
you know, i would love something like this landing page for all my servers apps
|
||||
that gives me the ability to pin favourites
|
||||
and / or search
|
||||
@Stark @Kode do either of you think you'd be able to rustle something like this up ?
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,56 +1,177 @@
|
||||
$.when( $.ready ).then(function() {
|
||||
|
||||
var base = (document.querySelector('base') || {}).href;
|
||||
|
||||
if($('.message-container').length) {
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
$('.message-container').fadeOut();
|
||||
}, 3500);
|
||||
function()
|
||||
{
|
||||
$('.message-container').fadeOut();
|
||||
}, 3500);
|
||||
}
|
||||
|
||||
if($('.livestats-container').length) {
|
||||
$('.livestats-container').each(function(index){
|
||||
// from https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
|
||||
// Set the name of the hidden property and the change event for visibility
|
||||
var hidden, visibilityChange;
|
||||
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
|
||||
hidden = "hidden";
|
||||
visibilityChange = "visibilitychange";
|
||||
} else if (typeof document.msHidden !== "undefined") {
|
||||
hidden = "msHidden";
|
||||
visibilityChange = "msvisibilitychange";
|
||||
} else if (typeof document.webkitHidden !== "undefined") {
|
||||
hidden = "webkitHidden";
|
||||
visibilityChange = "webkitvisibilitychange";
|
||||
}
|
||||
|
||||
var livestatsRefreshTimeouts = [];
|
||||
var livestatsFuncs = [];
|
||||
var livestatsContainers = $('.livestats-container');
|
||||
function stopLivestatsRefresh() {
|
||||
for (var timeoutId of livestatsRefreshTimeouts) {
|
||||
window.clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
function startLivestatsRefresh() {
|
||||
for (var fun of livestatsFuncs) {
|
||||
fun();
|
||||
}
|
||||
}
|
||||
|
||||
if (livestatsContainers.length > 0) {
|
||||
if (typeof document.addEventListener === "undefined" || hidden === undefined) {
|
||||
console.log("This browser does not support visibilityChange");
|
||||
} else {
|
||||
document.addEventListener(visibilityChange, function() {
|
||||
if (document[hidden]) {
|
||||
stopLivestatsRefresh();
|
||||
} else {
|
||||
startLivestatsRefresh();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
livestatsContainers.each(function(index){
|
||||
var id = $(this).data('id');
|
||||
var dataonly = $(this).data('dataonly');
|
||||
var increaseby = (dataonly == 1) ? 20000 : 1000;
|
||||
var container = $(this);
|
||||
var max_timer = 30000;
|
||||
var timer = 5000;
|
||||
(function worker() {
|
||||
var fun = function worker() {
|
||||
$.ajax({
|
||||
url: '/get_stats/'+id,
|
||||
success: function(data) {
|
||||
container.html(data);
|
||||
if(data != '') timer = increaseby;
|
||||
else {
|
||||
if(timer < max_timer) timer += 2000;
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
url: base+'get_stats/'+id,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
container.html(data.html);
|
||||
if(data.status == 'active') timer = increaseby;
|
||||
else {
|
||||
if(timer < max_timer) timer += 2000;
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
// Schedule the next request when the current one's complete
|
||||
setTimeout(worker, timer);
|
||||
}
|
||||
livestatsRefreshTimeouts[index] = window.setTimeout(worker, timer);
|
||||
}
|
||||
});
|
||||
})();
|
||||
};
|
||||
livestatsFuncs[index] = fun;
|
||||
fun();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$( "#sortable" ).sortable({
|
||||
function readURL(input) {
|
||||
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
$('#appimage img').attr('src', e.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$('#upload').change(function() {
|
||||
readURL(this);
|
||||
});
|
||||
/*$(".droppable").droppable({
|
||||
tolerance: "intersect",
|
||||
drop: function( event, ui ) {
|
||||
var tag = $( this ).data('id');
|
||||
var item = $( ui.draggable ).data('id');
|
||||
|
||||
$.get('tag/add/'+tag+'/'+item, function(data) {
|
||||
if(data == 1) {
|
||||
$( ui.draggable ).remove();
|
||||
} else {
|
||||
alert('not added');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});*/
|
||||
|
||||
$( '#sortable' ).sortable({
|
||||
stop: function (event, ui) {
|
||||
var idsInOrder = $("#sortable").sortable('toArray', {
|
||||
var idsInOrder = $('#sortable').sortable('toArray', {
|
||||
attribute: 'data-id'
|
||||
});
|
||||
$.post(
|
||||
'/order',
|
||||
base+'order',
|
||||
{ order:idsInOrder }
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
$("#sortable").sortable("disable");
|
||||
|
||||
|
||||
});
|
||||
$('#sortable').sortable('disable');
|
||||
|
||||
$('#sortable').on('mouseenter', '.item', function () {
|
||||
$(this).siblings('.tooltip').addClass('active')
|
||||
$('.refresh', this).addClass('active')
|
||||
}).on('mouseleave', '.item', function () {
|
||||
$(this).siblings('.tooltip').removeClass('active')
|
||||
$('.refresh', this).removeClass('active')
|
||||
})
|
||||
|
||||
$('#search-container').on('input', 'input[name=q]', function () {
|
||||
const search = this.value
|
||||
const items = $('#sortable').children('.item-container')
|
||||
if($('#search-container select[name=provider]').val() === 'tiles') {
|
||||
if(search.length > 0) {
|
||||
items.hide()
|
||||
items.filter(function () {
|
||||
const name = $(this).data('name').toLowerCase();
|
||||
return name.includes(search.toLowerCase())
|
||||
}).show()
|
||||
} else {
|
||||
items.show()
|
||||
}
|
||||
} else {
|
||||
items.show()
|
||||
}
|
||||
}).on('change', 'select[name=provider]', function () {
|
||||
const items = $('#sortable').children('.item-container')
|
||||
if($(this).val() === 'tiles') {
|
||||
$('#search-container button').hide()
|
||||
const search = $('#search-container input[name=q]').val()
|
||||
if(search.length > 0) {
|
||||
items.hide()
|
||||
items.filter(function () {
|
||||
const name = $(this).data('name').toLowerCase();
|
||||
return name.includes(search.toLowerCase())
|
||||
}).show()
|
||||
} else {
|
||||
items.show()
|
||||
}
|
||||
} else {
|
||||
$('#search-container button').show()
|
||||
items.show()
|
||||
}
|
||||
})
|
||||
|
||||
$('#app').on('click', '#config-button', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
@@ -60,61 +181,57 @@ $.when( $.ready ).then(function() {
|
||||
$('.add-item').hide();
|
||||
$('.item-edit').hide();
|
||||
$('#app').removeClass('sidebar');
|
||||
$("#sortable").sortable("disable")
|
||||
$('#sortable').sortable('disable');
|
||||
} else {
|
||||
$("#sortable").sortable("enable")
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
$('.add-item').fadeIn();
|
||||
$('.item-edit').fadeIn();
|
||||
}, 350);
|
||||
|
||||
$('#sortable').sortable('enable');
|
||||
setTimeout(function() {
|
||||
$('.add-item').fadeIn();
|
||||
$('.item-edit').fadeIn();
|
||||
}, 350);
|
||||
|
||||
}
|
||||
}).on('click', '#add-item, #pin-item', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
var active = (app.hasClass('sidebar'));
|
||||
app.toggleClass('sidebar');
|
||||
|
||||
|
||||
}).on('click', '.close-sidenav', function(e) {
|
||||
e.preventDefault();
|
||||
var app = $('#app');
|
||||
app.removeClass('sidebar');
|
||||
|
||||
|
||||
}).on('click', '#test_config', function(e) {
|
||||
e.preventDefault();
|
||||
var apiurl = $('#create input[name=url]').val();
|
||||
|
||||
|
||||
var override_url = $('#create input[name=override_url]');
|
||||
if(override_url.length && override_url.val() != '') {
|
||||
|
||||
var override_url = $('#create input[name="config[override_url]"]').val();
|
||||
if(override_url.length && override_url != '') {
|
||||
apiurl = override_url;
|
||||
}
|
||||
|
||||
var data = {};
|
||||
data['url'] = apiurl;
|
||||
$('input.config-item').each(function(index){
|
||||
$('.config-item').each(function(index){
|
||||
var config = $(this).data('config');
|
||||
data[config] = $(this).val();
|
||||
})
|
||||
});
|
||||
|
||||
$.post(
|
||||
'/test_config',
|
||||
{ data }, function(data) {
|
||||
alert(data);
|
||||
}
|
||||
);
|
||||
$.post(base+'test_config', { data: data }, function(data) {
|
||||
alert(data);
|
||||
});
|
||||
|
||||
});
|
||||
$('#pinlist').on('click', 'a', function(e) {
|
||||
e.preventDefault();
|
||||
var current = $(this);
|
||||
var id = current.data('id');
|
||||
$.get('items/pintoggle/'+id+'/true', function(data) {
|
||||
var tag = current.data('tag');
|
||||
$.get(base+'items/pintoggle/'+id+'/true/'+tag, function(data) {
|
||||
var inner = $(data).filter('#sortable').html();
|
||||
$('#sortable').html(inner);
|
||||
current.toggleClass('active');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -7,12 +7,111 @@ html {
|
||||
body {
|
||||
background: $body-bg;
|
||||
}
|
||||
|
||||
#switchuser {
|
||||
background: rgba(0,0,0,0.5);
|
||||
position: absolute;
|
||||
padding: 10px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
bottom:0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top: 2px solid rgba(255, 255, 255, 0.15);
|
||||
border-right: 2px solid rgba(255, 255, 255, 0.15);
|
||||
box-shadow: 0 0 10px 0px rgba(0, 0, 0, 0.4);
|
||||
border-radius: 0 9px 0 0;
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
img {
|
||||
width: 50px;
|
||||
margin-bottom: 5px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.btn {
|
||||
font-size: 13px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
margin-bottom: -10px;
|
||||
margin-top: 8px;
|
||||
border-radius: 0;
|
||||
width: calc(100% + 22px);
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
transition: all .35s ease-in-out;
|
||||
&:hover {
|
||||
background: #d64d55;
|
||||
}
|
||||
}
|
||||
}
|
||||
#tile-preview {
|
||||
align-items: center;
|
||||
}
|
||||
.create {
|
||||
.textarea {
|
||||
width: 100%;
|
||||
margin: 0px 20px;
|
||||
textarea{
|
||||
width: 100%;
|
||||
border: 1px solid #dedfe2;
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
height: 100px;
|
||||
font-size: 14px;
|
||||
}
|
||||
label:not(.switch) {
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
color: lighten($app-text, 40%);
|
||||
margin-bottom: 15px;
|
||||
display: block;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
.appoptions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
gap: 5px;
|
||||
.optdetails {
|
||||
display: flex;
|
||||
.input {
|
||||
margin: 0 20px;
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
.optvalue {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
width: auto;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
button.dark {
|
||||
background: #1b1b1b;
|
||||
border: none;
|
||||
padding: 12px 15px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
min-width: 240px;
|
||||
}
|
||||
}
|
||||
#app {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
background-image: url('/img/bg1.jpg');
|
||||
background-image: url('../img/bg1.jpg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: bottom center;
|
||||
@@ -70,7 +169,7 @@ body {
|
||||
flex-direction: column;
|
||||
}
|
||||
main, #sortable {
|
||||
padding: 10px;
|
||||
padding: 30px 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -104,6 +203,47 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.userlist {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.user {
|
||||
background: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 20px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 15px;
|
||||
border: 5px solid rgba(255,255,255, 0.7);
|
||||
box-shadow: 0 0 10px 0px rgba(0,0,0,0.4);
|
||||
}
|
||||
.user-img {
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 50%;
|
||||
margin: 10px 10px 15px;
|
||||
}
|
||||
#password {
|
||||
color: $app-text;
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
margin: 15px -5px;
|
||||
}
|
||||
.btn {
|
||||
width: 100%;
|
||||
}
|
||||
.forgot {
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.item-container {
|
||||
//width: 340px;
|
||||
//transition: width .35s ease-in-out;
|
||||
@@ -120,8 +260,68 @@ body {
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
display: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
padding: 25px;
|
||||
border-radius: 5px;
|
||||
background: #000000c8;
|
||||
color: white;
|
||||
position: absolute;
|
||||
bottom: 120px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
font-size: 13px;
|
||||
backdrop-filter: blur(8px);
|
||||
z-index: 0;
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
transition: all 0.3s;
|
||||
&.active {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
z-index: 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tile-actions {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0;
|
||||
padding: 7px;
|
||||
background: #000000d9;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
border-radius: 6px;
|
||||
width: 80px;
|
||||
height: 90px;
|
||||
display: flex;
|
||||
opacity: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.refresh {
|
||||
z-index: 3;
|
||||
.icon {
|
||||
font-size: 20px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
.black {
|
||||
color: #000!important;
|
||||
}
|
||||
.white {
|
||||
color: #fff!important;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
@@ -287,6 +487,8 @@ body {
|
||||
max-width: 1000px;
|
||||
width: 100%;
|
||||
margin: 10px 40px;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
header, footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -345,6 +547,8 @@ body {
|
||||
padding: 20px 25px;
|
||||
font-size: 13px;
|
||||
color: $app-text;
|
||||
max-width: 500px;
|
||||
word-break: break-word;
|
||||
&.form-error {
|
||||
background: #e69191;
|
||||
color: white;
|
||||
@@ -357,10 +561,30 @@ body {
|
||||
}
|
||||
}
|
||||
}
|
||||
.homesearch {
|
||||
height: 51px;
|
||||
}
|
||||
|
||||
.toggleinput {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
line-height: 1;
|
||||
font-size: 9px;
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
color: #ababab;
|
||||
padding: 0 20px;
|
||||
label.name {
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.module-actions {
|
||||
display: flex;
|
||||
justify-content:space-between;
|
||||
align-items: center;
|
||||
align-items: center;
|
||||
|
||||
|
||||
.button {
|
||||
font-size: 18px;
|
||||
@@ -400,6 +624,15 @@ body {
|
||||
}
|
||||
}
|
||||
}
|
||||
.input {
|
||||
position: relative;
|
||||
.help {
|
||||
position: absolute;
|
||||
bottom: -22px;
|
||||
left: 10px;
|
||||
color: #c00;
|
||||
}
|
||||
}
|
||||
div.create {
|
||||
padding: 30px 15px;
|
||||
display: flex;
|
||||
@@ -423,10 +656,19 @@ div.create {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app-icon-container {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 15px;
|
||||
flex: 0 0 60px;
|
||||
}
|
||||
.app-icon {
|
||||
max-width: 60px;
|
||||
margin-right: 15px;
|
||||
display: block;
|
||||
max-height: 60px;
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
@@ -465,6 +707,41 @@ div.create {
|
||||
color: #91a1b3;
|
||||
margin-left: 20px;
|
||||
}
|
||||
#websiteiconoptions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
.results {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.selectclose {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.iconbutton {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.selecticon {
|
||||
max-width: 120px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
@@ -582,7 +859,9 @@ div.create {
|
||||
border-bottom: 1px solid rgba(255,255,255,0.35);
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
max-width: 620px;
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
form {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -592,6 +871,8 @@ div.create {
|
||||
box-shadow: 0px 0px 5px 0 rgba(0,0,0,0.4);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
}
|
||||
input {
|
||||
padding: 17px 15px;
|
||||
@@ -615,6 +896,12 @@ div.create {
|
||||
text-transform: uppercase;
|
||||
background: $app-red;
|
||||
}
|
||||
select {
|
||||
padding: 0 10px;
|
||||
background: #f5f5f5;
|
||||
border: none;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-autocomplete {
|
||||
@@ -665,16 +952,17 @@ div.create {
|
||||
|
||||
#appimage {
|
||||
img {
|
||||
max-width: 150px;
|
||||
width: 95px;
|
||||
}
|
||||
}
|
||||
|
||||
#sapconfig {
|
||||
#sapconfig, .newblock {
|
||||
display: none;
|
||||
width: 100%;
|
||||
h2 {
|
||||
background: #f2f3f6;
|
||||
padding: 18px 25px;
|
||||
padding: 2px 25px;
|
||||
height: 60px;
|
||||
margin-left: -15px;
|
||||
width: calc(100% + 30px);
|
||||
/* margin-right: -30px; */
|
||||
@@ -683,6 +971,9 @@ div.create {
|
||||
font-size: 18px;
|
||||
color: #5b5b5b;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.items {
|
||||
display: flex;
|
||||
@@ -746,18 +1037,13 @@ hr {
|
||||
|
||||
.livestats-container {
|
||||
.livestats {
|
||||
margin: 5px 0px -5px;
|
||||
margin: 5px 0px 0px;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
list-style: none;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
li {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
span {
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
@@ -765,12 +1051,44 @@ hr {
|
||||
font-weight: 500;
|
||||
opacity: 0.5;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
text-align: left;
|
||||
}
|
||||
strong {
|
||||
display: block;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
li {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
&.right {
|
||||
text-align: right;
|
||||
span {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.flexcolumn {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
}
|
||||
&.black {
|
||||
.livestats {
|
||||
strong {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
29
resources/assets/sass/_rune.scss
Normal file
29
resources/assets/sass/_rune.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
// This file were added as a supplement to RuneAudio application
|
||||
|
||||
.title-marquee {
|
||||
width: 125px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-top: 2px;
|
||||
> span, > strong {
|
||||
white-space: nowrap;
|
||||
transform: translate(0, 0);
|
||||
animation: marquee 8s linear;
|
||||
}
|
||||
.title {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
.no-marquee {
|
||||
.title {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes marquee {
|
||||
0% { transform: translate(0, 0); }
|
||||
20% { transform: translate(0, 0); }
|
||||
95% { transform: translate(-200%, 0); }
|
||||
100% { transform: translate(-200%, 0); }
|
||||
}
|
||||
486
resources/assets/sass/_select2.scss
vendored
Normal file
486
resources/assets/sass/_select2.scss
vendored
Normal file
@@ -0,0 +1,486 @@
|
||||
.select2-container {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
vertical-align: middle; }
|
||||
.select2-container .select2-selection--single {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: 28px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--single .select2-selection__rendered {
|
||||
display: block;
|
||||
padding-left: 8px;
|
||||
padding-right: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-selection--single .select2-selection__clear {
|
||||
position: relative; }
|
||||
.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
|
||||
padding-right: 8px;
|
||||
padding-left: 20px; }
|
||||
.select2-container .select2-selection--multiple {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
min-height: 39px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--multiple .select2-selection__rendered {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-left: 8px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-search--inline {
|
||||
float: left; }
|
||||
.select2-container .select2-search--inline .select2-search__field {
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
font-size: 100%;
|
||||
margin-top: 5px;
|
||||
padding: 0; }
|
||||
.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
|
||||
.select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -100000px;
|
||||
width: 100%;
|
||||
z-index: 1051; }
|
||||
|
||||
.select2-results {
|
||||
display: block; }
|
||||
|
||||
.select2-results__options {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.select2-results__option {
|
||||
padding: 6px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-results__option[aria-selected] {
|
||||
cursor: pointer; }
|
||||
|
||||
.select2-container--open .select2-dropdown {
|
||||
left: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--above {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--below {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-search--dropdown {
|
||||
display: block;
|
||||
padding: 4px; }
|
||||
.select2-search--dropdown .select2-search__field {
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
.select2-search--dropdown.select2-search--hide {
|
||||
display: none; }
|
||||
|
||||
.select2-close-mask {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
height: auto;
|
||||
width: auto;
|
||||
opacity: 0;
|
||||
z-index: 99;
|
||||
background-color: #fff;
|
||||
filter: alpha(opacity=0); }
|
||||
|
||||
.select2-hidden-accessible {
|
||||
border: 0 !important;
|
||||
clip: rect(0 0 0 0) !important;
|
||||
-webkit-clip-path: inset(50%) !important;
|
||||
clip-path: inset(50%) !important;
|
||||
height: 1px !important;
|
||||
overflow: hidden !important;
|
||||
padding: 0 !important;
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
white-space: nowrap !important; }
|
||||
|
||||
.select2-container--default .select2-selection--single {
|
||||
background-color: #fff;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
|
||||
display: none; }
|
||||
|
||||
.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
|
||||
.select2-container--default .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #dedfe2;
|
||||
border-radius: 4px;
|
||||
cursor: text; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px;
|
||||
width: 100%; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered li {
|
||||
list-style: none; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__placeholder {
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
float: left; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
margin-right: 10px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #f2f3f6;
|
||||
border: 1px solid #dedfe2;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
font-size: 13px;
|
||||
font-weight: 300;
|
||||
margin-top: 5px;
|
||||
padding: 5px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #333; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
|
||||
float: right; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--default.select2-container--focus .select2-selection--multiple {
|
||||
border: solid #dedfe2 1px;
|
||||
outline: 0; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection--multiple {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
|
||||
display: none; }
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa; }
|
||||
|
||||
.select2-container--default .select2-search--inline .select2-search__field {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
-webkit-appearance: textfield; }
|
||||
|
||||
.select2-container--default .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
|
||||
.select2-container--default .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
|
||||
.select2-container--default .select2-results__option[aria-disabled=true] {
|
||||
color: #999; }
|
||||
|
||||
.select2-container--default .select2-results__option[aria-selected=true] {
|
||||
background-color: #ddd; }
|
||||
|
||||
.select2-container--default .select2-results__option .select2-results__option {
|
||||
padding-left: 1em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__group {
|
||||
padding-left: 0; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -1em;
|
||||
padding-left: 2em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -2em;
|
||||
padding-left: 3em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -3em;
|
||||
padding-left: 4em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -4em;
|
||||
padding-left: 5em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -5em;
|
||||
padding-left: 6em; }
|
||||
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #5897fb;
|
||||
color: white; }
|
||||
|
||||
.select2-container--default .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic .select2-selection--single {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
outline: 0;
|
||||
background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||
background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||
background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-right: 10px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow {
|
||||
background-color: #ddd;
|
||||
border: none;
|
||||
border-left: 1px solid #aaa;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
border: none;
|
||||
border-right: 1px solid #aaa;
|
||||
border-radius: 0;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-selection--single {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
|
||||
background: transparent;
|
||||
border: none; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||
background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||
background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
|
||||
|
||||
.select2-container--classic .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text;
|
||||
outline: 0; }
|
||||
.select2-container--classic .select2-selection--multiple:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__rendered {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__clear {
|
||||
display: none; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #555; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-selection--multiple {
|
||||
border: 1px solid #5897fb; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--classic .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa;
|
||||
outline: 0; }
|
||||
|
||||
.select2-container--classic .select2-search--inline .select2-search__field {
|
||||
outline: 0;
|
||||
box-shadow: none; }
|
||||
|
||||
.select2-container--classic .select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid transparent; }
|
||||
|
||||
.select2-container--classic .select2-dropdown--above {
|
||||
border-bottom: none; }
|
||||
|
||||
.select2-container--classic .select2-dropdown--below {
|
||||
border-top: none; }
|
||||
|
||||
.select2-container--classic .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
|
||||
.select2-container--classic .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
|
||||
.select2-container--classic .select2-results__option[aria-disabled=true] {
|
||||
color: grey; }
|
||||
|
||||
.select2-container--classic .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #3875d7;
|
||||
color: white; }
|
||||
|
||||
.select2-container--classic .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-dropdown {
|
||||
border-color: #5897fb; }
|
||||
8
resources/assets/sass/app.scss
vendored
8
resources/assets/sass/app.scss
vendored
@@ -1,6 +1,6 @@
|
||||
|
||||
// Fonts
|
||||
@import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
|
||||
//@import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
|
||||
|
||||
// Variables
|
||||
@import "variables";
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
// Bootstrap
|
||||
@import "app";
|
||||
@import "rune";
|
||||
|
||||
// Huebee
|
||||
@import "huebee";
|
||||
|
||||
// fontawesome
|
||||
@import "fontawesome/fontawesome";
|
||||
@import "fontawesome/fa-solid";
|
||||
@import "select2";
|
||||
|
||||
|
||||
BIN
resources/assets/sass/fontawesome/.__animated.scss
vendored
BIN
resources/assets/sass/fontawesome/.__animated.scss
vendored
Binary file not shown.
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__core.scss
vendored
BIN
resources/assets/sass/fontawesome/.__core.scss
vendored
Binary file not shown.
Binary file not shown.
BIN
resources/assets/sass/fontawesome/.__icons.scss
vendored
BIN
resources/assets/sass/fontawesome/.__icons.scss
vendored
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user