mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-22 09:17:57 -04:00
Compare commits
655 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee7b982358 | ||
|
|
2740f36259 | ||
|
|
ff16810e76 | ||
|
|
161cfcd64d | ||
|
|
d16d1fdcd5 | ||
|
|
06c0652b05 | ||
|
|
a2fb2e04f3 | ||
|
|
b376f810bf | ||
|
|
0c2bcda431 | ||
|
|
22cb0d3c6b | ||
|
|
b6b4eb4c22 | ||
|
|
da1e0b965b | ||
|
|
d566199423 | ||
|
|
35be83c5f6 | ||
|
|
76eed3c06c | ||
|
|
d994e1be48 | ||
|
|
24316bbb03 | ||
|
|
7b5a638e00 | ||
|
|
fa4c86eabf | ||
|
|
9cf610280c | ||
|
|
052341d24a | ||
|
|
a55bba7aa8 | ||
|
|
0244d9423a | ||
|
|
042c98cf2d | ||
|
|
2958ea8c89 | ||
|
|
81a12be654 | ||
|
|
9f99e401bc | ||
|
|
48ef490f50 | ||
|
|
d782229ba0 | ||
|
|
52291fd371 | ||
|
|
e0298a4378 | ||
|
|
08b7eb52c7 | ||
|
|
43ebf69d09 | ||
|
|
18ae629f19 | ||
|
|
8deedd1979 | ||
|
|
525594d529 | ||
|
|
1162615c52 | ||
|
|
c462c928e0 | ||
|
|
fcb0ef9633 | ||
|
|
8a4273a2f5 | ||
|
|
3014ae2071 | ||
|
|
d396043faf | ||
|
|
2054359f6c | ||
|
|
9a3735cd37 | ||
|
|
222b74ec05 | ||
|
|
cb491c53f7 | ||
|
|
37f0074674 | ||
|
|
e6c8c47721 | ||
|
|
0a98a49eeb | ||
|
|
7bd4217dd8 | ||
|
|
af5733888c | ||
|
|
c346210735 | ||
|
|
6028f0490e | ||
|
|
890a5942d6 | ||
|
|
7782183ae3 | ||
|
|
7ecbce691d | ||
|
|
2aeed27b9b | ||
|
|
d636e71024 | ||
|
|
2606517c1d | ||
|
|
0ab94d42f4 | ||
|
|
7c32b11605 | ||
|
|
7b6c76abf1 | ||
|
|
0e31d61868 | ||
|
|
66e02c5e3a | ||
|
|
122747ae76 | ||
|
|
9a410f57e6 | ||
|
|
2047e9bca7 | ||
|
|
aeb54655a0 | ||
|
|
1a3ca49eba | ||
|
|
579cf86335 | ||
|
|
fcf42eeae0 | ||
|
|
721c0b1e5b | ||
|
|
82b2f06bdd | ||
|
|
b241e14c06 | ||
|
|
89c17bac50 | ||
|
|
e6bd5ef520 | ||
|
|
7320149fd8 | ||
|
|
7766e5d420 | ||
|
|
4a813c150c | ||
|
|
44600c46c6 | ||
|
|
b5c7fff316 | ||
|
|
ce618facc8 | ||
|
|
18016ab36a | ||
|
|
d788233bd7 | ||
|
|
86ebef7e08 | ||
|
|
37159937d7 | ||
|
|
4d6d3befa0 | ||
|
|
a21785980d | ||
|
|
14fe08240f | ||
|
|
73d50d8294 | ||
|
|
767eeee6fe | ||
|
|
abd864a762 | ||
|
|
25dba4423b | ||
|
|
2046abf26f | ||
|
|
ad7871270c | ||
|
|
66512f4e51 | ||
|
|
71a06af8a9 | ||
|
|
14088b4b2e | ||
|
|
ec2c4fe673 | ||
|
|
49a065e50b | ||
|
|
391c8d7cba | ||
|
|
76296e72be | ||
|
|
d36f806ece | ||
|
|
d3d8c088f3 | ||
|
|
4e01e21230 | ||
|
|
673790126b | ||
|
|
9eecd0aa3c | ||
|
|
f8fb1bc3b4 | ||
|
|
340f5bb791 | ||
|
|
5504c8650e | ||
|
|
9405f2e2d3 | ||
|
|
3de0d304fd | ||
|
|
0e4924d7c5 | ||
|
|
20377c1ca1 | ||
|
|
8af9bbb75e | ||
|
|
34c3a77db4 | ||
|
|
dbc3613af5 | ||
|
|
e1d395b6ed | ||
|
|
5316ebfe7c | ||
|
|
13755060d7 | ||
|
|
eeb8a124fc | ||
|
|
5db855abfe | ||
|
|
ab14743146 | ||
|
|
409c062c4f | ||
|
|
1b494cdd27 | ||
|
|
f5f853cdfe | ||
|
|
37aa16a6c0 | ||
|
|
a4ebf93cb8 | ||
|
|
358e7c9512 | ||
|
|
11b42a371e | ||
|
|
61da32dc3f | ||
|
|
5f26e77785 | ||
|
|
1d289e619e | ||
|
|
0c41265613 | ||
|
|
b5ad0589cb | ||
|
|
9e87070f86 | ||
|
|
3da16a4bae | ||
|
|
1ad76ec83f | ||
|
|
fa67852278 | ||
|
|
d9ebd880be | ||
|
|
9d7c5d2fe2 | ||
|
|
8c268d24df | ||
|
|
f8fb550255 | ||
|
|
c1aa5a2954 | ||
|
|
342f736eb7 | ||
|
|
0283c77961 | ||
|
|
7740a7501b | ||
|
|
ed97164f01 | ||
|
|
6649eca2bf | ||
|
|
64ae1eb5e8 | ||
|
|
d42a89d4b5 | ||
|
|
bb05f520c1 | ||
|
|
f8afa77369 | ||
|
|
940fd26db7 | ||
|
|
fca6ddd35b | ||
|
|
a5ded5884c | ||
|
|
d0686796cd | ||
|
|
3ea323bfb0 | ||
|
|
c826b307c2 | ||
|
|
00edbe4393 | ||
|
|
525a45f69c | ||
|
|
e35d4b6be0 | ||
|
|
83c963378e | ||
|
|
7705d7a87f | ||
|
|
3060126123 | ||
|
|
29f14ff96b | ||
|
|
8a8219fe72 | ||
|
|
0aef9b486d | ||
|
|
d584e4f7d5 | ||
|
|
71fbc3ff5c | ||
|
|
3613257cdc | ||
|
|
f61fd2d337 | ||
|
|
bd8ffcd28d | ||
|
|
20148d23f1 | ||
|
|
bdcee46138 | ||
|
|
bc40c3f7c0 | ||
|
|
7e3d86bc37 | ||
|
|
133ac409e3 | ||
|
|
bda32015b9 | ||
|
|
f0229c9f42 | ||
|
|
7cd44e2112 | ||
|
|
3a3ae2b204 | ||
|
|
4df3c8d2a1 | ||
|
|
8d1fea7ec3 | ||
|
|
3535cb3b96 | ||
|
|
48af5b354d | ||
|
|
19df2f596b | ||
|
|
51cd6381a6 | ||
|
|
311e0159c9 | ||
|
|
63c3f4dc20 | ||
|
|
b6e65a76ea | ||
|
|
d31221e61b | ||
|
|
043c1610fd | ||
|
|
84a4927866 | ||
|
|
2c3ec1ae81 | ||
|
|
5655962370 | ||
|
|
cd7fab3d37 | ||
|
|
980fedadc0 | ||
|
|
0121e4ed12 | ||
|
|
ea6893e3a3 | ||
|
|
8a211aff97 | ||
|
|
daf8531804 | ||
|
|
961996a051 | ||
|
|
0f8500244b | ||
|
|
5dcafde617 | ||
|
|
e101e4f511 | ||
|
|
a5e171a594 | ||
|
|
be35f612eb | ||
|
|
6d306bc0b3 | ||
|
|
813a5b3621 | ||
|
|
48162fc8d6 | ||
|
|
868f9a6b92 | ||
|
|
e022e59d0a | ||
|
|
9947f1ec99 | ||
|
|
6a2748724c | ||
|
|
457cb74883 | ||
|
|
90b8e08637 | ||
|
|
572b4a45da | ||
|
|
2e7f806c15 | ||
|
|
4ed8e7b469 | ||
|
|
1eb3357584 | ||
|
|
3850cd9641 | ||
|
|
6f501b37e8 | ||
|
|
456a741809 | ||
|
|
8a0c9648fe | ||
|
|
4625a8927c | ||
|
|
a773ca8a24 | ||
|
|
eb00fe3575 | ||
|
|
1666ca7cb7 | ||
|
|
89aecbbc1c | ||
|
|
7b8e47b49d | ||
|
|
cf317aa1a1 | ||
|
|
bd1e282499 | ||
|
|
d8a5e8c550 | ||
|
|
43d0e42425 | ||
|
|
c31b3b6b67 | ||
|
|
18be92ba22 | ||
|
|
2b38eca986 | ||
|
|
4ec895b891 | ||
|
|
757237cbb4 | ||
|
|
869b047fde | ||
|
|
4bf6752982 | ||
|
|
5c3f2f9469 | ||
|
|
6e21be2d94 | ||
|
|
3e07eb78fd | ||
|
|
dceaee691f | ||
|
|
7cf380e390 | ||
|
|
9165f766c2 | ||
|
|
d77d56dfb0 | ||
|
|
0ae938a4bf | ||
|
|
8a0ef4c809 | ||
|
|
a3f37e2f1e | ||
|
|
271b9f66ea | ||
|
|
4914438479 | ||
|
|
7a01eaa90f | ||
|
|
948ceb3fac | ||
|
|
d26a3ec22b | ||
|
|
c4a3c7feb7 | ||
|
|
6e8481e90e | ||
|
|
47d988419f | ||
|
|
a84e6e9747 | ||
|
|
aa9210921d | ||
|
|
e91f8f3aef | ||
|
|
9b36c39eff | ||
|
|
a28dd9f2cf | ||
|
|
bf79a2cf4f | ||
|
|
a03ca38409 | ||
|
|
1b246e2ba5 | ||
|
|
f905266e4b | ||
|
|
e511220022 | ||
|
|
5655807337 | ||
|
|
0930539ab4 | ||
|
|
b674a1869e | ||
|
|
16fafdbbb0 | ||
|
|
b5acde1420 | ||
|
|
4fa9f30189 | ||
|
|
57ae3325e0 | ||
|
|
8141ef9511 | ||
|
|
e70870ce4e | ||
|
|
7cb8a56b6a | ||
|
|
07ca5d54c8 | ||
|
|
dfde321a3b | ||
|
|
aab53c9fc9 | ||
|
|
9def0f280f | ||
|
|
e71c95a5a5 | ||
|
|
1be6c11bad | ||
|
|
030fe8c656 | ||
|
|
8f539e3707 | ||
|
|
918377a67b | ||
|
|
25e29ec544 | ||
|
|
71f80aa4d2 | ||
|
|
070d839ad9 | ||
|
|
ee9b53132e | ||
|
|
ca4bb5927e | ||
|
|
6ed56f9996 | ||
|
|
ac5d22d514 | ||
|
|
21279b7d4e | ||
|
|
77c310e393 | ||
|
|
c5d75f23e5 | ||
|
|
a00db63b3e | ||
|
|
1d60d38cdc | ||
|
|
0b42197a99 | ||
|
|
07da20d00c | ||
|
|
d413cf8a30 | ||
|
|
1da0ea86f0 | ||
|
|
72f36920ef | ||
|
|
7a4d568bfb | ||
|
|
0d1c5e26a7 | ||
|
|
ff0a5a0507 | ||
|
|
da780e4e08 | ||
|
|
0c783773d8 | ||
|
|
5edeb7bd53 | ||
|
|
20c8f69efa | ||
|
|
b694ed6229 | ||
|
|
b4f7daadfb | ||
|
|
fb3eae96ab | ||
|
|
cc91446c18 | ||
|
|
22bda936a5 | ||
|
|
95a2de4da2 | ||
|
|
ee3fc54be6 | ||
|
|
e2c477d775 | ||
|
|
6ddd31bfba | ||
|
|
3653f769d9 | ||
|
|
261f0e4120 | ||
|
|
6fce724f69 | ||
|
|
dedab1ad4f | ||
|
|
cf1a404945 | ||
|
|
ac4af6f9ef | ||
|
|
69ade6d2cb | ||
|
|
6db5236bf5 | ||
|
|
b39fb945f5 | ||
|
|
3fcd5a0f0f | ||
|
|
62635aa803 | ||
|
|
32717d910c | ||
|
|
881f540e43 | ||
|
|
e5cd6330b3 | ||
|
|
e91021f648 | ||
|
|
1463c1a526 | ||
|
|
e195897dc7 | ||
|
|
b6f0fe7583 | ||
|
|
377fe32795 | ||
|
|
73d444bd8a | ||
|
|
80415f6bd3 | ||
|
|
7ab531025c | ||
|
|
763a4f1fbb | ||
|
|
cde558a43f | ||
|
|
bafbbc9d5b | ||
|
|
ad4eec1145 | ||
|
|
0584094f05 | ||
|
|
c614f899b7 | ||
|
|
0940be57fd | ||
|
|
7e148c1e30 | ||
|
|
babc3df364 | ||
|
|
ba9637e129 | ||
|
|
a48a72d1cd | ||
|
|
1edea291a4 | ||
|
|
b7ef3fab3c | ||
|
|
afe31160db | ||
|
|
4849d50610 | ||
|
|
d5f7b620c4 | ||
|
|
6515443957 | ||
|
|
8b352e4c64 | ||
|
|
7c59dd9fd7 | ||
|
|
118a223ee1 | ||
|
|
481113f641 | ||
|
|
bed929c966 | ||
|
|
10345a5418 | ||
|
|
efc9581798 | ||
|
|
005b9919d0 | ||
|
|
86e88c6bb0 | ||
|
|
7505f7039a | ||
|
|
5a52b6afea | ||
|
|
86f8d8ecdf | ||
|
|
81559e9bcf | ||
|
|
1b458c7d65 | ||
|
|
d2177f27f9 | ||
|
|
da6db54122 | ||
|
|
1e41c83b35 | ||
|
|
8bc079aa3d | ||
|
|
a5a58d73ff | ||
|
|
68967e93d6 | ||
|
|
88f1a7d652 | ||
|
|
21c2fabae0 | ||
|
|
a36afc0bb7 | ||
|
|
7855aaf53c | ||
|
|
6535475a99 | ||
|
|
ddaaac1103 | ||
|
|
295266cb10 | ||
|
|
e800d176fb | ||
|
|
cace4c6c65 | ||
|
|
d7aff9a4dd | ||
|
|
a4a7794315 | ||
|
|
c1d87fa65d | ||
|
|
e69763f86d | ||
|
|
5db5a5cfe9 | ||
|
|
24f71dfcf8 | ||
|
|
6d62acb446 | ||
|
|
32ab6344c4 | ||
|
|
60b4c003af | ||
|
|
4c962417ff | ||
|
|
d2aad8a41a | ||
|
|
fd0f6d4fa8 | ||
|
|
87d68b175e | ||
|
|
64652c1d6e | ||
|
|
9342a92682 | ||
|
|
443c5495e9 | ||
|
|
80f3892ba0 | ||
|
|
16ee954048 | ||
|
|
4e367e1e67 | ||
|
|
7f7763ee0c | ||
|
|
868a8ccfd9 | ||
|
|
b7b1a5574f | ||
|
|
aa0c8973fa | ||
|
|
f6b91f97bf | ||
|
|
d82e7c9f6c | ||
|
|
083b2b1bbc | ||
|
|
805bbd1c3e | ||
|
|
077ca1aea5 | ||
|
|
1217ae3b3e | ||
|
|
17777981ac | ||
|
|
ddc4bdcebe | ||
|
|
126c7f9d62 | ||
|
|
75d1be092e | ||
|
|
0d51ff1906 | ||
|
|
679b5098da | ||
|
|
224b32e767 | ||
|
|
1f943474cb | ||
|
|
6891db1b23 | ||
|
|
a19951528d | ||
|
|
a4ea4ecc3b | ||
|
|
8c182c9d68 | ||
|
|
384eea79dc | ||
|
|
c2a09434ca | ||
|
|
6068c0e8c2 | ||
|
|
f8bc755c20 | ||
|
|
fd86ccb4eb | ||
|
|
c36d159997 | ||
|
|
efd61cb43a | ||
|
|
aa38e8360a | ||
|
|
fdf6680b29 | ||
|
|
b79c19c66d | ||
|
|
8999a96ef0 | ||
|
|
b5d2236a58 | ||
|
|
91e59d3c4f | ||
|
|
a6ff444e19 | ||
|
|
ee4cc51a05 | ||
|
|
29d4edb285 | ||
|
|
7c79ec9626 | ||
|
|
66f793cb83 | ||
|
|
6d926f4271 | ||
|
|
6ffd3fd9d4 | ||
|
|
3d204c782b | ||
|
|
20f8239b44 | ||
|
|
10c2bd83d3 | ||
|
|
4b02bd60cb | ||
|
|
50ea3afcb0 | ||
|
|
982d7540cc | ||
|
|
b9aec78dde | ||
|
|
f5b1fda6b7 | ||
|
|
4dfdb2b2e1 | ||
|
|
a5a2d80c50 | ||
|
|
8da7fe8dbe | ||
|
|
f64c5977f8 | ||
|
|
a16e024b51 | ||
|
|
860de5e28e | ||
|
|
b38da72535 | ||
|
|
2c4f1dcf03 | ||
|
|
0a1255518f | ||
|
|
a822e94f9b | ||
|
|
484971c90a | ||
|
|
e11035acf4 | ||
|
|
3d522b99d8 | ||
|
|
e62c4e6088 | ||
|
|
703ccc2a9a | ||
|
|
b2d09134c1 | ||
|
|
de3f491966 | ||
|
|
322a021765 | ||
|
|
d191b66bb8 | ||
|
|
5241a159d2 | ||
|
|
fe8ae2f88e | ||
|
|
3550609d29 | ||
|
|
c6df3b0b97 | ||
|
|
e6ca21965b | ||
|
|
c44c522d7d | ||
|
|
f48bf8e366 | ||
|
|
6e1cdebbf4 | ||
|
|
eb592bb741 | ||
|
|
db5d67a4e0 | ||
|
|
6e390a06e1 | ||
|
|
295d5f06dc | ||
|
|
30d552255e | ||
|
|
0522bd5593 | ||
|
|
a46d837267 | ||
|
|
bee493f628 | ||
|
|
a4f4a082af | ||
|
|
dd9ab07044 | ||
|
|
afd811a875 | ||
|
|
122d46b79b | ||
|
|
36448adad4 | ||
|
|
8f93d9aa75 | ||
|
|
76f50d7150 | ||
|
|
80c9880a67 | ||
|
|
d1f54507f6 | ||
|
|
334852d733 | ||
|
|
362be52be0 | ||
|
|
20f5e654ad | ||
|
|
34b2bdcf2c | ||
|
|
8c38ee8208 | ||
|
|
2c1c12825d | ||
|
|
5188b9cef5 | ||
|
|
8c0b7ce4de | ||
|
|
17d0d6f75d | ||
|
|
bbcf7e9aa1 | ||
|
|
45a2ebc662 | ||
|
|
aece22aee6 | ||
|
|
9904eba277 | ||
|
|
7c0f98a513 | ||
|
|
8d25b6eae4 | ||
|
|
9369085835 | ||
|
|
059113d2a8 | ||
|
|
f60dff788e | ||
|
|
9c20b4809a | ||
|
|
00b3039b6e | ||
|
|
2695094d16 | ||
|
|
bcfdb73001 | ||
|
|
1650809cd8 | ||
|
|
991815469f | ||
|
|
c5fb8eafac | ||
|
|
a0c98e070e | ||
|
|
7d6202be13 | ||
|
|
4ba470318c | ||
|
|
e948aaf751 | ||
|
|
3789017ca0 | ||
|
|
48f5acced3 | ||
|
|
13e2d2f654 | ||
|
|
8d45fd36a1 | ||
|
|
6ed2301a94 | ||
|
|
a0eb701503 | ||
|
|
39f9a38b23 | ||
|
|
590c0ea778 | ||
|
|
f36d8e4bd2 | ||
|
|
4e3bec8a35 | ||
|
|
eec918bf4a | ||
|
|
13002af4c3 | ||
|
|
40c63a7f12 | ||
|
|
3d0621eb8c | ||
|
|
030c02dfdc | ||
|
|
00c1509549 | ||
|
|
8122c40252 | ||
|
|
787c63b7ae | ||
|
|
ee988edc83 | ||
|
|
a71f5e123a | ||
|
|
7579749adc | ||
|
|
cf408c3fac | ||
|
|
0c97792ca7 | ||
|
|
84d63b3b67 | ||
|
|
63aa50eb8d | ||
|
|
7fb13f23fe | ||
|
|
65156a0e4d | ||
|
|
e3eebcd95d | ||
|
|
9eff1a08d4 | ||
|
|
cfcac590c3 | ||
|
|
872415bffe | ||
|
|
a46b781664 | ||
|
|
b77fac43c8 | ||
|
|
2b4b409c01 | ||
|
|
67aa547c48 | ||
|
|
e288f33776 | ||
|
|
a5aab4c30e | ||
|
|
cf7613b3e0 | ||
|
|
fa01a2b348 | ||
|
|
65c8de3410 | ||
|
|
d9b262348f | ||
|
|
ea9d2a0acf | ||
|
|
5d55006be8 | ||
|
|
d9ced0c6bf | ||
|
|
8d4d1b17c7 | ||
|
|
453f6a08a3 | ||
|
|
b6560e5456 | ||
|
|
b805f48c32 | ||
|
|
33b78a4943 | ||
|
|
48b187ccd8 | ||
|
|
f680bba3e6 | ||
|
|
09aabc6b41 | ||
|
|
0dd456c653 | ||
|
|
97ba14cbe0 | ||
|
|
ee6367a549 | ||
|
|
fc52d1b44f | ||
|
|
bfce562a46 | ||
|
|
8d8a7f44e1 | ||
|
|
6c8da6ce36 | ||
|
|
e19a050b92 | ||
|
|
a13bf6a3fe | ||
|
|
0edf761499 | ||
|
|
bf76d5981f | ||
|
|
33fcb43173 | ||
|
|
ffae47f523 | ||
|
|
c07cdb30fa | ||
|
|
546c4fcad2 | ||
|
|
0a17b83578 | ||
|
|
2782b6d724 | ||
|
|
dc076a4c00 | ||
|
|
a550c7c853 | ||
|
|
7a3d59bff3 | ||
|
|
82a3b71a51 | ||
|
|
e39b2eb7b9 | ||
|
|
9f8248cc9c | ||
|
|
71e4326606 | ||
|
|
7eb6f9b11d | ||
|
|
4625ffa6b4 | ||
|
|
3e6a646603 | ||
|
|
324b281813 | ||
|
|
03d1f3383e | ||
|
|
69a23c604d | ||
|
|
174469970a | ||
|
|
89b254dc1c | ||
|
|
8e51988e96 | ||
|
|
52e279f443 | ||
|
|
4efa853690 | ||
|
|
9b13055dfe | ||
|
|
06afd8a375 | ||
|
|
6f027544d6 | ||
|
|
2d2c9fa519 | ||
|
|
27efb887d2 | ||
|
|
ccd52584a4 | ||
|
|
ab0fdb13d4 | ||
|
|
2bca44ed25 | ||
|
|
eab08d0bcb | ||
|
|
d3f00704bd | ||
|
|
1e1a7109a9 | ||
|
|
ebab5ff281 | ||
|
|
0165f44063 | ||
|
|
5fb6e5d6f7 | ||
|
|
8fc0e41beb | ||
|
|
3ad63a6e82 | ||
|
|
5a84ffdcda | ||
|
|
ad993645be | ||
|
|
392cb020aa | ||
|
|
0701cde239 | ||
|
|
a136c288d5 | ||
|
|
884b612ffc | ||
|
|
ae0d138d2a | ||
|
|
1624a2620a | ||
|
|
48ef4744ac | ||
|
|
a17cb75baf | ||
|
|
f4769d0f04 | ||
|
|
c8e30a00e2 | ||
|
|
169c971cb1 | ||
|
|
51745d3652 | ||
|
|
3ebbb91ae9 | ||
|
|
762d402dea | ||
|
|
051cef79fc | ||
|
|
b05a440f03 | ||
|
|
9bb4988eda | ||
|
|
f66f0e398b |
@@ -27,23 +27,21 @@ if you look for more choices. The main differences are:
|
||||
- graphical installer whiptail
|
||||
- The script stops (fails) if it finds results of a previous installation. (The [debian-setup.sh](https://framagit.org/ojrandom/core/-/tree/dev/.debianinstall) will just jump over it.)
|
||||
- If something fails the script tries to clean up everything that was installed up to the point of failure. (That might cause trouble if certbot registered a certificate already.)
|
||||
- The script under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall) seems to be an older version of the scripts used for Streams
|
||||
+ [autoinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/autoinstall)
|
||||
+ [easyinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/easyinstall)
|
||||
- The script under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall) seems to be an older version of the scripts used for Streams, i.e. [autoinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/autoinstall) and [easyinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/easyinstall)
|
||||
|
||||
## Preconditions
|
||||
|
||||
Hardware
|
||||
|
||||
+ internet connection and router at home
|
||||
+ computer connected to your router (a Raspberry 3 will do for very small Hubs)
|
||||
+ computer connected to your router (a Raspberry 4 will do for very small Hubs)
|
||||
|
||||
Software
|
||||
|
||||
+ fresh installation of Debian 12 (bookworm)
|
||||
+ fresh installation of Debian 12 (bookworm) or Raspberry Pi OS
|
||||
+ router with open ports 80 and 443 for your web server
|
||||
|
||||
You can of course run the script on a VPS or any distant server as long as the above sotfware requirements are satisfied.
|
||||
You can of course run the script on a VPS or any distant server as long as the above software requirements are satisfied.
|
||||
|
||||
## How to run the script
|
||||
|
||||
@@ -82,6 +80,11 @@ Switch the verification off
|
||||
|
||||
util/config system verify_email 0
|
||||
|
||||
Check if updates from the repository do work
|
||||
|
||||
util/udall
|
||||
|
||||
|
||||
## What the script will do for you...
|
||||
|
||||
+ install everything required by your hubzilla instance, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||
@@ -101,7 +104,7 @@ The script is known to work without adjustments with
|
||||
|
||||
+ Hardware
|
||||
- standard PC with Debian 12 (bookworm)
|
||||
- Raspberry 4 with Raspbian, Debian 12 (TODO: needs confirmation after swich to Debian12)
|
||||
- Raspberry 5 with Raspberry Pi OS, Debian 12
|
||||
- for tesing purposes: under localhost inside a virtual machine, [KVM](https://wiki.debian.org/KVM)
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
@@ -151,8 +154,3 @@ It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
## Reminder for Different Web Wervers
|
||||
|
||||
For those of you who feel adventurous enough to use a different web server (i.e. Lighttpd...), don't forget that this script will install Apache or Nginx and that you can only have one web server listening to ports 80 & 443. Also, don't forget to tweak your daily shell script in /var/www/ accordingly.
|
||||
|
||||
@@ -93,9 +93,8 @@ freedns_key=
|
||||
# If left empty, both your database and user will be named after your zot instance (hubzilla, zap or misty)
|
||||
# Use custom name, at least fo the database, if you plan to run more than one hub/instance on the same server
|
||||
#
|
||||
zotserver_db_name=
|
||||
zotserver_db_user=
|
||||
zotserver_db_pass=$db_pass
|
||||
db_name=hubzilla
|
||||
db_user=hubzilla
|
||||
#
|
||||
#
|
||||
# Password for package mysql-server
|
||||
|
||||
@@ -150,7 +150,7 @@ function install_sendmail {
|
||||
function install_php {
|
||||
# openssl and mbstring are included in libapache2-mod-php
|
||||
print_info "installing php..."
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip"
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip php-intl php-bcmath"
|
||||
phpversion=$(php -v|grep --only-matching --perl-regexp "(PHP )\d+\.\\d+\.\\d+"|cut -c 5-7)
|
||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/$phpversion/apache2/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/$phpversion/apache2/php.ini
|
||||
@@ -160,8 +160,8 @@ function install_composer {
|
||||
print_info "We check if Composer is already downloaded"
|
||||
if [ ! -f /usr/local/bin/composer ]
|
||||
then
|
||||
EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
|
||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
EXPECTED_CHECKSUM="`wget -qO- https://composer.github.io/installer.sig`"
|
||||
wget https://getcomposer.org/installer -O composer-setup.php
|
||||
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
||||
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
|
||||
then
|
||||
@@ -171,6 +171,7 @@ function install_composer {
|
||||
fi
|
||||
php composer-setup.php --quiet
|
||||
RESULT=$?
|
||||
composer --version
|
||||
rm composer-setup.php
|
||||
# exit $RESULT
|
||||
# We install Composer globally
|
||||
@@ -181,7 +182,7 @@ function install_composer {
|
||||
fi
|
||||
cd $install_path
|
||||
export COMPOSER_ALLOW_SUPERUSER=1;
|
||||
/usr/local/bin/composer install --no-dev
|
||||
/usr/local/bin/composer install --no-dev --quiet
|
||||
/usr/local/bin/composer show
|
||||
export COMPOSER_ALLOW_SUPERUSER=0;
|
||||
}
|
||||
@@ -256,12 +257,18 @@ function create_zotserver_db {
|
||||
then
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $db_user@localhost IDENTIFIED BY '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $db_name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
else
|
||||
echo "database $db_name does exist already"
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $db_user@localhost IDENTIFIED BY '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $db_name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -301,10 +308,19 @@ function install_run_selfhost {
|
||||
# https://carol.selfhost.de/update?username=123456&password=supersafe
|
||||
#
|
||||
# the prefered way
|
||||
wget --output-document=$selfhostdir/$selfhostscript http://jonaspasche.de/selfhost-updater
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
if [ ! -f $selfhostdir/$selfhostscript ]
|
||||
then
|
||||
wget --output-document=$selfhostdir/$selfhostscript https://jonaspasche.de/selfhost-updater
|
||||
if [ ! -s $selfhostdir/$selfhostscript ]
|
||||
then
|
||||
die "Failed to download selfHOST file for dynDNS"
|
||||
fi
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
print_info "Wrote file to update dynamic IP. File: $selfhostdir/$selfhostscript"
|
||||
fi
|
||||
print_info "executing $selfhostdir/$selfhostscript update..."
|
||||
bash $selfhostdir/$selfhostscript update
|
||||
fi
|
||||
}
|
||||
@@ -380,7 +396,7 @@ function install_letsencrypt {
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||
fi
|
||||
nocheck_install "certbot python-certbot-apache"
|
||||
nocheck_install "certbot python3-certbot-apache"
|
||||
print_info "run certbot ..."
|
||||
certbot --apache -w $install_path -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
|
||||
service apache2 restart
|
||||
@@ -435,7 +451,7 @@ function configure_cron_daily {
|
||||
echo "echo \" \"" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - stopping apache and mysql...\"" >> /var/www/$cron_job
|
||||
echo "service apache2 stop" >> /var/www/$cron_job
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /var/www/$cron_job
|
||||
echo "systemctl stop mysql.service # to avoid inconsistencies" >> /var/www/$cron_job
|
||||
echo "#" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$cron_job
|
||||
echo "certbot renew --noninteractive" >> /var/www/$cron_job
|
||||
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -48,9 +48,10 @@ doc/html/
|
||||
.zotshrc
|
||||
# external repositories for themes/addons
|
||||
extend/
|
||||
# files generated by phpunit
|
||||
|
||||
# exclude test results and cache
|
||||
tests/.cache
|
||||
tests/.phpunit.result.cache
|
||||
tests/.phpunit*
|
||||
tests/results/
|
||||
|
||||
## exclude IDE files
|
||||
@@ -67,7 +68,6 @@ nbproject/
|
||||
# PHPStorm
|
||||
.idea/
|
||||
|
||||
|
||||
## composer
|
||||
# locally installed composer binary
|
||||
composer.phar
|
||||
@@ -87,6 +87,7 @@ vendor/bin/php-parse
|
||||
vendor/bin/phpcbf
|
||||
vendor/bin/phpcs
|
||||
vendor/bin/phpmd
|
||||
vendor/bin/phpstan*
|
||||
vendor/bin/phpunit
|
||||
vendor/composer/pcre/
|
||||
vendor/composer/xdebug-handler/
|
||||
@@ -98,18 +99,11 @@ vendor/pdepend/
|
||||
vendor/phar-io/
|
||||
vendor/php-mock/
|
||||
vendor/phpmd/
|
||||
vendor/phpstan
|
||||
vendor/phpunit/
|
||||
vendor/psr/container/
|
||||
vendor/sebastian/
|
||||
vendor/squizlabs/
|
||||
vendor/symfony/config/
|
||||
vendor/symfony/dependency-injection/
|
||||
vendor/symfony/deprecation-contracts/
|
||||
vendor/symfony/filesystem/
|
||||
vendor/symfony/polyfill-ctype/
|
||||
vendor/symfony/polyfill-mbstring/
|
||||
vendor/symfony/polyfill-php80/
|
||||
vendor/symfony/service-contracts/
|
||||
vendor/theseer/
|
||||
# /info is a directory containing site-specific HTML documents
|
||||
/info/
|
||||
|
||||
@@ -32,7 +32,8 @@ before_script:
|
||||
- apt-get install -yqq libicu-dev libjpeg-dev libpng-dev libpq-dev libyaml-dev libzip-dev mariadb-client postgresql-client unzip zip
|
||||
- pecl install xdebug yaml
|
||||
- docker-php-ext-enable xdebug yaml
|
||||
- docker-php-ext-install gd bcmath intl pdo_mysql pdo_pgsql zip
|
||||
- docker-php-ext-configure gd --with-jpeg=/usr/include/
|
||||
- docker-php-ext-install gd bcmath intl pdo_mysql pdo_pgsql zip exif
|
||||
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
@@ -58,7 +59,7 @@ before_script:
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
# Run the actual tests
|
||||
- touch dbfail.out
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- vendor/bin/phpunit -d memory_limit=256M --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
|
||||
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
|
||||
|
||||
@@ -83,7 +84,7 @@ before_script:
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
|
||||
# Run the actual tests
|
||||
- touch dbfail.out
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- vendor/bin/phpunit -d memory_limit=256M --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
|
||||
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
|
||||
|
||||
|
||||
212
CHANGELOG
212
CHANGELOG
@@ -1,3 +1,215 @@
|
||||
Hubzilla 10.4 (2025-07-15)
|
||||
- Add support for did:key verification method to checkEddsaSignature()
|
||||
- Introduce util/init_sys_channel to create the sys channel if required
|
||||
- Update norwegian translations
|
||||
- Add init_sys_channel utility to create the sys channel in case of headless installation or failure
|
||||
- Upgrade http-message-signer to version 2.3
|
||||
- Upgrade phpseclib to version 3
|
||||
- Minor cleanup to the account functions and added tests
|
||||
- Do not sign (request-target) on response
|
||||
- Start verifying incoming RFC9421 HTTP signatures
|
||||
- Convert geo URIs into clickable links
|
||||
- Allow geo URIs in url bbcode tags
|
||||
- Cleanup obsolete and unused functions
|
||||
- Remove unused Xref module
|
||||
- Make sure we have the keys before attempting to sign with JcsEddsa2022
|
||||
- Implement lazy loading of toplevel comments
|
||||
- Update german help files
|
||||
- Add App::$page_layouts attribute for comanche
|
||||
- Refactor and fix numerous issues in guess_image_type()
|
||||
- Add tests for Widget\Messages
|
||||
- Refactor cache_embeds daemon to be called with uuid (instead of item id) so that it will only be processed once
|
||||
- Add avif support for php-gd
|
||||
- Exclude Add/Remove items from network nouveau query
|
||||
- Always preload images and remove pre image preload setting
|
||||
- Introduce per channel conversation mode setting
|
||||
- Add API docs for the observer file
|
||||
- Move observer helper functions to separate source
|
||||
- Introduce helper functions to access the various fields of the xchan stored in App::$observer
|
||||
- Refactor item_normal() to accept an owner uid
|
||||
- Implement reply modal if comment replies are enabled
|
||||
- Streamline wording conversation > comment > reply
|
||||
- Streamline default ordering to created date
|
||||
- Default to threaded conversation mode
|
||||
- Implement lazy loading of reactions
|
||||
- Do not store dismissed create activities in dreport
|
||||
- Refactor mod item to deprecate x() and use $_POST instead of $_REQUEST superglobal
|
||||
- Improved styling for dreport module
|
||||
- Start deprecation of the function x()
|
||||
- Minor cleanup and refactor for Web/Router
|
||||
- Minor cleanup and refactor for Lib/Webserver
|
||||
- Set App::$query_string from from server.request_uri instead of server.query_string because the latter will mostly be urldecoded by the server already
|
||||
- Refactor language selector
|
||||
- Extend message filter to support until=2025-04-18 20:49:00 for date/time based filtering and add tests
|
||||
- Extend message filter to deal with && and || conditions and add tests
|
||||
- Prevent storing files/folder with filenames exceeding their max name length
|
||||
- Deal with attachment of type link
|
||||
- Revert translation of network to stream
|
||||
- Updated debian install script
|
||||
- Add suport for strong bbcode tag
|
||||
- Change photo.filename to type text for new installs
|
||||
- Provide methods to get mid and uuid from activity object
|
||||
- Minor update for boxy schema
|
||||
- Update composer libs
|
||||
- Reorganize emojis and allow custom site emojis
|
||||
- Change item.obj and item.target to mediumtext for mysql new installs
|
||||
- Move jot related functions to jot-header and some cleanup
|
||||
- Port photo selector to vanilla javascript
|
||||
- Enable photo selector for comments if OCAP access is enabled
|
||||
- Add :hubzilla: emoji
|
||||
- Add :zot: emoji
|
||||
- Include unapproved connections in deliverable_abook_xchans()
|
||||
- Port showHideComments() to vanilla javascript
|
||||
- Disable browser rotating image based on EXIF metadata
|
||||
|
||||
Bugfixes
|
||||
- Fix blog mode if threaded view is disabled
|
||||
- Fix markdown issue with mentions
|
||||
- Fix issue where item_wall was not set for article and card item types
|
||||
- Fix first created account was not necessarily the admin account
|
||||
- Fix notice not emited on failed login
|
||||
- Fix intro notifications not handled via /notify/view and hence not marked seen
|
||||
- Fix undefined static function in Zot6Handler
|
||||
- Fix missing return in Render\Theme::current
|
||||
- Fix announce source title (addr) not correct
|
||||
- Fix offset calculation if element position is relative
|
||||
- Fix autosave for comments
|
||||
- Fix notfication issue with update activities
|
||||
- Fix sess_data not updated to mediumtext in mysql schema file
|
||||
- Fix title and summary converted to bbcode
|
||||
- Fix preloading images if dom element is not yet in page
|
||||
- Fix verb and hash for notifications
|
||||
- Fix notification button for medium screen size (right aside collapsed)
|
||||
- Fix new result set created for updated results (dreport)
|
||||
- Fix regex to catch codeblocks with params like class in smilies()
|
||||
- Fix term.imgurl not stored in item_store_update()
|
||||
- Fix folder names are not URL escaped in Files app (issue #1903)
|
||||
- Fix stephenhill/base58 PHP warnings
|
||||
- Fix color bbcode markup
|
||||
- Fix video poster display issue
|
||||
- Fix relayed emoji reactions
|
||||
- Fix some javascript errors on mobile devices
|
||||
- Fix our own activities visible in unseen forum notifications
|
||||
- Fix duplicated head_get_icon()
|
||||
|
||||
Addons
|
||||
- Wiki: fix spacing in wikilist widget
|
||||
- Gallery: look for templates in theme directory first
|
||||
- Articles: look for templates in theme directory first
|
||||
- Wiki: look for templates in theme directory first
|
||||
- Pubcrawl: remove unused force note setting
|
||||
- Flashcards: major refactor and added functionality
|
||||
- Superblock: refactor and new siteblock option for admins
|
||||
- Cart: fix issue related to HTTP3
|
||||
- Pubcrawl: avoid DB lookup if not valid AS request in mod followers and mod following
|
||||
- Photocache: implement prefetch via cache_embeds daemon and minor refactor
|
||||
- Articles: fix Add/Remove activities not dismissed in channel activities query
|
||||
- Cards: fix Add/Remove activities not dismissed in channel activities query
|
||||
- Diaspora: make sure item_thread_top is set for reshares (info for filters)
|
||||
- Gallery: fix missing folder field from query
|
||||
- Pubcrawl: update mod ap_probe to show a visual representation if applicable
|
||||
|
||||
|
||||
Hubzilla 10.2.3 (2025-04-11)
|
||||
- Fix bogus merge from 10.2.2 release
|
||||
|
||||
|
||||
Hubzilla 10.2.2 (2025-04-11)
|
||||
- Cleanup deprecated forum queries, improved performance
|
||||
- Fix zot6 handler returning success allthough Libzot::fetch() did not return anything useful
|
||||
- Fix json encoding of a possibly empty item.target
|
||||
- Fix permalink for forum posts and comments
|
||||
- Fix an obscure delivering issue which could produce duplicate posts
|
||||
- Lazy load profile photos for reactions to reduce server load
|
||||
- Pubcrawl: deal with Update(Tombstone)
|
||||
- Pubcrawl: fix mentions not mapped to "to" in public toplevel posts (regression)
|
||||
|
||||
|
||||
Hubzilla 10.2.1 (2025-03-18)
|
||||
- Fix OWA in cases where Signature is in the REDIRECT_REMOTE_USER field
|
||||
- Fix query in mod sse_bs
|
||||
|
||||
|
||||
Hubzilla 10.2 (2025-03-17)
|
||||
- Allow to send signed requests from the zot_probe tool
|
||||
- Print an error message if OWA fails
|
||||
- Remove possible leading @ before processing webfinger address
|
||||
- Updated debian install script
|
||||
- Calculate observer.baseurl from xchan_url instead of xchan_connurl
|
||||
- Refactor unparse_url() to allow return of a custom field set only and add tests
|
||||
- Slightly improve event object rendering
|
||||
- Update smarty library to version 5 for PHP 8.4 compatibility
|
||||
- Remove vendor/symfony from gitignore file
|
||||
- Update composer libraries
|
||||
- Add contextHistory field to activities and prefer it over context when consuming
|
||||
- Implement highlight button in jot editor
|
||||
- Add test results and PHPStan to gitignore
|
||||
- Update spanish strings
|
||||
- Remove EpubMeta library in favor of a custom solution
|
||||
- Configue gd for jpeg support in CI
|
||||
- Add error message on missing owa auth headers
|
||||
- Add Zotlabs\Tests namespace to autloader in dev
|
||||
- Add dba_pdo::update method
|
||||
- Add dba_pdo::insert method
|
||||
- Rewrite redbasic javascript to remove jquery dependency
|
||||
- Add security policy SECURITY.md
|
||||
|
||||
Bugfixes
|
||||
- Fix notifications for likes on our comments
|
||||
- Fix fullscreen view
|
||||
- Fix boxy scheme text alignment for comments
|
||||
- Fix poll date string to match with the autotime string
|
||||
- Fix owner hash not set correctly when editing a post/comment
|
||||
- Fix an issue where some participants could not post to forums
|
||||
- Fix navbar selector conflict with possible additional navbars when using a cover photo
|
||||
- Fix target and tgt_type not set for sourced rss items if we rewrite them to our own
|
||||
- Fix auto save draft not set correctly
|
||||
- Fix cover height calculation
|
||||
|
||||
Addons
|
||||
- Diaspora: revisit import_diaspora_account()
|
||||
- Pubcrawl: escape quotation marks in ActivityStreams link header
|
||||
- Wiki: fixed wiki_page_list.tpl to use bootstrap class for layout
|
||||
- BBmath: fix orientation for inline math
|
||||
- BBmath: document imagemagick permissions
|
||||
- Pubcrawl: ensure we select the correct hubloc hash when extending recipients list
|
||||
- Msg_footer: do not add footer on edit, also dismiss anything but a create activity
|
||||
- Pubcrawl: refactor activitypub addressing
|
||||
- Wiki: added space to preview panel
|
||||
- Startpage: update help text and some cleanup
|
||||
|
||||
|
||||
Hubzilla 10.0.8 (2025-02-01)
|
||||
- Fix duplicating terms/iconfig in addToCollectionAndSync()
|
||||
- Refactor Daemon/Importdoc for better SQL performance when looking up outdated entries
|
||||
- Tweak SQL in mod sse_bs for possible performance improvements
|
||||
- Fix PHP warnings
|
||||
- Do not run post_local hook on add activities in pubcrawl addon
|
||||
- Do not run post_local hook on add activities in diaspora addon
|
||||
- Remove old rawmsg/fields before storing new rawmsg in pubcrawl addon
|
||||
- Fix retractions in diaspora addon
|
||||
|
||||
|
||||
Hubzilla 10.0.7 (2025-01-22)
|
||||
- Fix ownership check in consume_feed()
|
||||
- Fix toast() if notification contains non-ascii characters
|
||||
- Fix regression in notifications filter
|
||||
|
||||
|
||||
Hubzilla 10.0.6 (2025-01-05)
|
||||
- Fix entries where primary location data is not complete not dismissed early
|
||||
- Fix query to cleanup outdated doc entries called multiple times
|
||||
- Fix query to cleanup outdated doc entries
|
||||
|
||||
|
||||
Hubzilla 10.0.5 (2024-12-29)
|
||||
- Fix another instance of drop_item() not having permission to drop items
|
||||
|
||||
|
||||
Hubzilla 10.0.4 (2024-12-26)
|
||||
- Fix missing argument name
|
||||
|
||||
|
||||
Hubzilla 10.0.3 (2024-12-26)
|
||||
- Fix regression in Daemon/Channel_purge which could cause a possible infinite loop
|
||||
- Fix regression in Daemon/Expire which could cause a infinite loop
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
"air" is a branch name for revision of Account-Invite-Register at the Hubzilla project
|
||||
|
||||
Invite:
|
||||
* Rewritten and now language template driven
|
||||
* Selectable templates for the invite mails
|
||||
* Invitor may add personal notes in the mailtext
|
||||
+ Invite codes are bound to the recipients email address
|
||||
* Invite mod never more creates accounts
|
||||
* new db scheme for table register
|
||||
* existing register table will be migrated to the new schema even when detected at runtime
|
||||
* Bugfix: creating invite codes when admin only calls Invite w/o any further action
|
||||
* account library revision also together with invite mod
|
||||
* Depending on config: Users may send invitations also
|
||||
* Invitations expires, controlled by the invitor
|
||||
* Changed and new configs:
|
||||
* * invitation_only As usual before
|
||||
* * invitation_also Beside other registration policies, invitations may be used also
|
||||
* * invitation_max_per_day defaults 50, may be changed in adminUI admin>site
|
||||
* * invitation_max_per_user defaults 4
|
||||
* Requirements:
|
||||
* * Addon language has to be installed
|
||||
|
||||
Register:
|
||||
* Register panel (form) and js interaction changed
|
||||
* Unused registrations expire
|
||||
* Depending on config, anonymous registrations (w/o email) are supported
|
||||
* :... dont't panic, that may let grow security
|
||||
* Even anonymous users have to confirm their registration
|
||||
* Registrations may be enabled / disabled time driven for each day in the week (dudy)
|
||||
* Unsoliced registration floods may be blocked
|
||||
* Limited registrations from one single source ip
|
||||
* Using one additional log file, to easy interfare with f2b
|
||||
|
||||
Account:
|
||||
* An user account always becomes created only if all depending conditions are satisfied
|
||||
* AdminUI for site configuration, accounts and registrations enhancements
|
||||
* Still untouched, but accountUI needs enhanced async control in case for mass delete
|
||||
with deep level of recursion cascade of the dependencies (channels etc). An open TODO
|
||||
since years for instances with many much users and channels.
|
||||
|
||||
History:
|
||||
2020.03 Hubzilla Prod version 4.6 (master branch) of hubzilla/core was the base for AIR
|
||||
that was assigned Version 4.6.2 at sn/core
|
||||
2021.02 Hubzilla Prod version 5.2.1 (master branch) of hubzilla/core was new base for AIR
|
||||
that was assigned version 5.2.2 at sn/core (air.5)
|
||||
plus adjustment of hubzilla 5.2.2 (master) to sn/core (air.5) version 5.2.9
|
||||
|
||||
|
||||
31
SECURITY.md
Normal file
31
SECURITY.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Hubzilla Security Policy
|
||||
|
||||
The [Hubzilla] Project takes security, privacy and user control over personal data seriously. We ask that any security issues be disclosed to us in a responsible manner to allow us time to remediate the issues, and site administrators time to upgrade before information about the issue is made public.
|
||||
|
||||
This document outlines security procedures and policies for the Hubzilla project. It covers the following components:
|
||||
|
||||
* The Hubzilla core repository: https://framagit.org/hubzilla/core
|
||||
* The official addon repository: https://framagit.org/hubzilla/addons
|
||||
* The official themes repository: https://framagit.org/hubzilla/themes
|
||||
* The official widgets repository: https://framagit.org/hubzilla/widgets
|
||||
|
||||
## Coordinated Disclosure Guidelines
|
||||
|
||||
We are committed to working with security researchers to verify, reproduce, and respond to legitimate reported vulnerabilities. You can help us by following these simple guidelines:
|
||||
|
||||
* Submit suspected vulnerabilities by email to `security@hubzilla.org`, or as a confidential issue in the relevant repository listed above.
|
||||
* Provide clear instructions on how to reproduce the issue, and if possible, a minimal Proof of Concept (PoC) exploit.
|
||||
* We will acknowledge your submission as soon as we can, and will keep you updated as it is being processed. We may ask for more information, or clarifications about the issue or the steps to reproduce it during this time.
|
||||
* We will assign a CVE to the issue once it is confirmed.
|
||||
* We will do our best to fix the issue as soon as we can after it has been confirmed. We request that information about the vulnerability or details about how to exploit it is not disclosed to other parties until after the fix is released and some time has passed, to allow site administrators to upgrade. We will normally make the CVE public one month after a fix has been released. (This grace period can differ based on severity, and can be negotiated.)
|
||||
* Please perform all tests against a local instance of the software, and refrain from running any Denial of Service or automated testing tools against public hubs or the project managers (and their partners') infrastructure.
|
||||
* If the issue belongs to a third party module that we depend on, we may help with reporting it upstream if the submitter wants us to.
|
||||
|
||||
## Comments on this Policy
|
||||
|
||||
We welcome comments and suggestions for improving this policy. You can reach us at:
|
||||
|
||||
* Our ticketing system: https://framagit.org/hubzilla/core/-/issues
|
||||
* By sending us an email at `security@hubzilla.org`.
|
||||
|
||||
[Hubzilla]: https://hubzilla.org
|
||||
@@ -6,23 +6,28 @@ class Cache_embeds {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
if(! $argc == 2)
|
||||
if(!$argc == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
$c = q("select body from item where id = %d ",
|
||||
dbesc(intval($argv[1]))
|
||||
$c = q("select uid, aid, body, item_private from item where uuid = '%s'",
|
||||
dbesc($argv[1])
|
||||
);
|
||||
|
||||
if(! $c)
|
||||
if(!$c) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item = $c[0];
|
||||
|
||||
// bbcode conversion by default processes embeds that aren't already cached.
|
||||
// Ignore the returned html output.
|
||||
|
||||
bbcode($item['body']);
|
||||
|
||||
// photocache addon hook to prefetch one copy of public item images for the sys channel
|
||||
call_hooks('cache_prefetch_hook', $item);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class Channel_purge {
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rv) {
|
||||
drop_item($rv['id'], $channel_id);
|
||||
drop_item($rv['id'], uid: $channel_id);
|
||||
}
|
||||
}
|
||||
} while ($r);
|
||||
|
||||
@@ -125,14 +125,15 @@ class Cron {
|
||||
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(Config::Get('system', 'cache_expire_days', 7) . ' DAY')
|
||||
db_quoteinterval(Config::Get('system', 'default_expire_days', 30) . ' DAY')
|
||||
);
|
||||
if ($r) {
|
||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(Config::Get('system', 'cache_expire_days', 7) . ' DAY')
|
||||
db_quoteinterval(Config::Get('system', 'default_expire_days', 30) . ' DAY')
|
||||
);
|
||||
|
||||
foreach ($r as $rr) {
|
||||
$file = dbunescbin($rr['content']);
|
||||
if (is_file($file)) {
|
||||
|
||||
@@ -11,6 +11,21 @@ class Importdoc {
|
||||
|
||||
self::update_docs_dir('doc/*');
|
||||
|
||||
$sys = get_sys_channel();
|
||||
|
||||
// remove old files that weren't updated (indicates they were most likely deleted).
|
||||
$i = q("select id from item where uid = %d and item_type = 5 and edited < %s - INTERVAL %s",
|
||||
intval($sys['channel_id']),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('14 DAY')
|
||||
);
|
||||
|
||||
if ($i) {
|
||||
foreach ($i as $iv) {
|
||||
drop_item($iv['id'], uid: $sys['channel_id']);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@@ -41,18 +56,6 @@ class Importdoc {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove old files that weren't updated (indicates they were most likely deleted).
|
||||
$i = q("select * from item where item_type = 5 and edited < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval('14 DAY', true)
|
||||
);
|
||||
|
||||
if ($i) {
|
||||
foreach ($i as $iv) {
|
||||
drop_item($iv['id'], DROPITEM_NORMAL, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -323,7 +323,13 @@ class Notifier {
|
||||
self::$encoded_item = json_decode($m, true);
|
||||
}
|
||||
else {
|
||||
self::$encoded_item = Activity::build_packet(Activity::encode_activity($target_item), self::$channel, false);
|
||||
$activity = Activity::encode_activity($target_item);
|
||||
|
||||
if (!$activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$encoded_item = Activity::build_packet($activity, self::$channel, false);
|
||||
}
|
||||
|
||||
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
|
||||
@@ -340,6 +346,10 @@ class Notifier {
|
||||
|
||||
$relay_to_owner = (!$top_level_post && intval($target_item['item_origin']) && comment_local_origin($target_item));
|
||||
|
||||
if (self::$channel['channel_hash'] === $target_item['owner_xchan']) {
|
||||
$relay_to_owner = false;
|
||||
}
|
||||
|
||||
// $cmd === 'relay' indicates the owner is sending it to the original recipients
|
||||
// don't allow the item in the relay command to relay to owner under any circumstances, it will loop
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ use Zotlabs\Entity\Item;
|
||||
require_once('include/event.php');
|
||||
require_once('include/html2plain.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/markdown.php');
|
||||
|
||||
class Activity {
|
||||
|
||||
@@ -68,10 +69,10 @@ class Activity {
|
||||
if ($j) {
|
||||
xchan_query($j, true);
|
||||
$items = fetch_post_tags($j);
|
||||
}
|
||||
|
||||
if ($items) {
|
||||
return self::encode_item(array_shift($items));
|
||||
if ($items) {
|
||||
return self::encode_item(array_shift($items));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -165,7 +166,7 @@ class Activity {
|
||||
}
|
||||
else {
|
||||
logger('fetch failed: ' . $url);
|
||||
logger($x['body']);
|
||||
logger(print_r($x, true), LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
|
||||
@@ -580,14 +581,12 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if (intval($i['item_wall'])) {
|
||||
$ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'], 'post_comments'));
|
||||
}
|
||||
|
||||
if (intval($i['item_private']) === 2) {
|
||||
$ret['directMessage'] = true;
|
||||
}
|
||||
|
||||
$ret['commentPolicy'] = (($i['item_wall']) ? map_scope(PermissionLimits::Get($i['uid'], 'post_comments')) : '');
|
||||
|
||||
if (array_key_exists('comments_closed', $i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] > NULL_DATE) {
|
||||
if ($ret['commentPolicy']) {
|
||||
$ret['commentPolicy'] .= ' ';
|
||||
@@ -616,6 +615,7 @@ class Activity {
|
||||
if (!empty($cnv)) {
|
||||
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
|
||||
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
|
||||
$ret['contextHistory'] = $cnv;
|
||||
}
|
||||
$ret['context'] = $cnv;
|
||||
}
|
||||
@@ -694,7 +694,7 @@ class Activity {
|
||||
if (is_array($t) && !array_key_exists('type', $t))
|
||||
$t['type'] = 'Hashtag';
|
||||
|
||||
if (is_array($t) && (array_key_exists('href', $t) || array_key_exists('id', $t)) && array_key_exists('name', $t)) {
|
||||
if (is_array($t) && (array_key_exists('href', $t) || array_key_exists('id', $t) || isset($t['icon']['url'])) && array_key_exists('name', $t)) {
|
||||
switch ($t['type']) {
|
||||
case 'Hashtag':
|
||||
$ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])];
|
||||
@@ -709,7 +709,7 @@ class Activity {
|
||||
break;
|
||||
|
||||
case 'Emoji':
|
||||
$ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['id'], 'term' => escape_tags($t['name']), 'imgurl' => $t['icon']['url']];
|
||||
$ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['id'] ?? $t['icon']['url'], 'term' => escape_tags($t['name']), 'imgurl' => $t['icon']['url']];
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -802,7 +802,7 @@ class Activity {
|
||||
|
||||
$ret = [];
|
||||
|
||||
if (isset($item['attachment'])) {
|
||||
if (isset($item['attachment']) && is_array($item['attachment'])) {
|
||||
$ptr = $item['attachment'];
|
||||
if (!array_key_exists(0, $ptr)) {
|
||||
$ptr = [$ptr];
|
||||
@@ -852,6 +852,8 @@ class Activity {
|
||||
$entry['type'] = $att['mediaType'];
|
||||
} elseif (array_key_exists('type', $att) && $att['type'] === 'Image') {
|
||||
$entry['type'] = 'image/jpeg';
|
||||
} elseif (array_key_exists('type', $att) && $att['type'] === 'Link') {
|
||||
$entry['type'] = 'text/uri-list';
|
||||
}
|
||||
if (array_key_exists('name', $att) && $att['name']) {
|
||||
$entry['name'] = html2plain(purify_html($att['name']), 256);
|
||||
@@ -941,36 +943,8 @@ class Activity {
|
||||
|
||||
}
|
||||
|
||||
if ($ret['type'] === 'emojiReaction') {
|
||||
// There may not be an object for these items for legacy reasons - it should be the conversation parent.
|
||||
$p = q("select * from item where mid = '%s' and uid = %d",
|
||||
dbesc($i['parent_mid']),
|
||||
intval($i['uid'])
|
||||
);
|
||||
if ($p) {
|
||||
xchan_query($p, true);
|
||||
$p = fetch_post_tags($p);
|
||||
$i['obj'] = self::encode_item($p[0]);
|
||||
|
||||
// convert to zot6 emoji reaction encoding which uses the target object to indicate the
|
||||
// specific emoji instead of overloading the verb or type.
|
||||
|
||||
$im = explode('#', $i['verb']);
|
||||
if ($im && count($im) > 1)
|
||||
$emoji = $im[1];
|
||||
if (preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
|
||||
$ln = $match[2];
|
||||
}
|
||||
|
||||
$i['tgt_type'] = 'Image';
|
||||
|
||||
$i['target'] = [
|
||||
'type' => 'Image',
|
||||
'name' => $emoji,
|
||||
'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
|
||||
];
|
||||
|
||||
}
|
||||
if ($ret['type'] === 'EmojiReact') {
|
||||
$ret['content'] = $i['body'];
|
||||
}
|
||||
|
||||
if (strpos($i['mid'], z_root() . '/item/') !== false) {
|
||||
@@ -985,15 +959,15 @@ class Activity {
|
||||
|
||||
$ret['diaspora:guid'] = $i['uuid'];
|
||||
|
||||
if (isset($i['title']) && $i['title'])
|
||||
$ret['name'] = html2plain(bbcode($i['title'], ['cache' => true]));
|
||||
if (!empty($i['title']))
|
||||
$ret['name'] = html2plain(bbcode($i['title']));
|
||||
|
||||
if (isset($i['summary']) && $i['summary'])
|
||||
$ret['summary'] = bbcode($i['summary'], ['cache' => true]);
|
||||
if (!empty($i['summary']))
|
||||
$ret['summary'] = bbcode($i['summary']);
|
||||
|
||||
if ($ret['type'] === 'Announce') {
|
||||
$tmp = preg_replace('/\[share(.*?)\[\/share\]/ism', EMPTY_STR, $i['body']);
|
||||
$ret['content'] = bbcode($tmp, ['cache' => true]);
|
||||
$ret['content'] = bbcode($tmp);
|
||||
$ret['source'] = [
|
||||
'content' => $i['body'],
|
||||
'mediaType' => 'text/bbcode'
|
||||
@@ -1009,7 +983,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($i['app']) && $i['app']) {
|
||||
if (!empty($i['app'])) {
|
||||
$ret['generator'] = ['type' => 'Application', 'name' => $i['app']];
|
||||
}
|
||||
if (!empty($i['location']) || !empty($i['coord'])) {
|
||||
@@ -1050,6 +1024,7 @@ class Activity {
|
||||
if (!empty($cnv)) {
|
||||
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
|
||||
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
|
||||
$ret['contextHistory'] = $cnv;
|
||||
}
|
||||
$ret['context'] = $cnv;
|
||||
}
|
||||
@@ -1060,7 +1035,7 @@ class Activity {
|
||||
else
|
||||
return [];
|
||||
|
||||
if (isset($i['obj']) && $i['obj']) {
|
||||
if (!empty($i['obj'])) {
|
||||
if (!is_array($i['obj'])) {
|
||||
$i['obj'] = json_decode($i['obj'], true);
|
||||
}
|
||||
@@ -1088,7 +1063,7 @@ class Activity {
|
||||
$ret['type'] = 'Invite';
|
||||
}
|
||||
|
||||
if (isset($i['target']) && $i['target']) {
|
||||
if (!empty($i['target'])) {
|
||||
if (!is_array($i['target'])) {
|
||||
$i['target'] = json_decode($i['target'], true);
|
||||
}
|
||||
@@ -1099,12 +1074,10 @@ class Activity {
|
||||
return [];
|
||||
}
|
||||
|
||||
/* this should not be needed
|
||||
$t = self::encode_taxonomy($i);
|
||||
if ($t) {
|
||||
$ret['tag'] = $t;
|
||||
}
|
||||
*/
|
||||
|
||||
$a = self::encode_attachment($i, true);
|
||||
if ($a) {
|
||||
@@ -1115,7 +1088,6 @@ class Activity {
|
||||
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
|
||||
}
|
||||
|
||||
|
||||
$hookinfo = [
|
||||
'item' => $i,
|
||||
'encoded' => $ret
|
||||
@@ -1716,9 +1688,9 @@ class Activity {
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $person_obj['name'] ?? '';
|
||||
$name = ((isset($person_obj['name'])) ? escape_tags($person_obj['name']) : '');
|
||||
if (!$name) {
|
||||
$name = $person_obj['preferredUsername'] ?? '';
|
||||
$name = ((isset($person_obj['preferredUsername'])) ? escape_tags($person_obj['preferredUsername']) : '');
|
||||
}
|
||||
if (!$name) {
|
||||
$name = t('Unknown');
|
||||
@@ -1727,13 +1699,11 @@ class Activity {
|
||||
$webfinger_addr = ((isset($person_obj['webfinger'])) ? str_replace('acct:', '', $person_obj['webfinger']) : '');
|
||||
$hostname = '';
|
||||
$baseurl = '';
|
||||
$site_url = '';
|
||||
|
||||
$m = parse_url($url);
|
||||
if ($m) {
|
||||
$hostname = $m['host'];
|
||||
$baseurl = $m['scheme'] . '://' . $m['host'] . ((isset($m['port'])) ? ':' . $m['port'] : '');
|
||||
$site_url = $m['scheme'] . '://' . $m['host'];
|
||||
$hostname = unparse_url($m, ['host']);
|
||||
$baseurl = unparse_url($m, ['scheme', 'host', 'port']);
|
||||
}
|
||||
|
||||
if (!$webfinger_addr && !empty($person_obj['preferredUsername']) && $hostname) {
|
||||
@@ -1835,7 +1805,7 @@ class Activity {
|
||||
|
||||
q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($site_url)
|
||||
dbesc($baseurl)
|
||||
);
|
||||
|
||||
// update existing xchan record
|
||||
@@ -2148,34 +2118,24 @@ class Activity {
|
||||
$s['owner_xchan'] = $act->actor['id'];
|
||||
$s['author_xchan'] = $act->actor['id'];
|
||||
|
||||
$content = [];
|
||||
|
||||
if (is_array($act->obj)) {
|
||||
$content = self::get_content($act->obj);
|
||||
}
|
||||
|
||||
$s['mid'] = $act->objprop('id');
|
||||
|
||||
if (!$s['mid'] && is_string($act->obj)) {
|
||||
$s['mid'] = $act->obj;
|
||||
}
|
||||
|
||||
// pleroma fetched activities
|
||||
if (!$s['mid'] && isset($act->obj['data']['id'])) {
|
||||
$s['mid'] = $act->obj['data']['id'];
|
||||
}
|
||||
|
||||
if ($act->objprop('type') === 'Profile') {
|
||||
$s['mid'] = $act->id;
|
||||
}
|
||||
$s['mid'] = self::getMessageID($act);
|
||||
|
||||
if (!$s['mid']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Friendica sends the diaspora guid in a nonstandard field via AP
|
||||
// If no uuid is provided we will create an uuid v5 from the mid
|
||||
$s['uuid'] = (($act->objprop('diaspora:guid')) ?: uuid_from_url($s['mid']));
|
||||
$s['uuid'] = self::getUUID($act);
|
||||
|
||||
if (!$s['uuid']) {
|
||||
// If we have not found anything useful, create an uuid v5 from the mid
|
||||
$s['uuid'] = uuid_from_url($s['mid']);
|
||||
}
|
||||
|
||||
$content = [];
|
||||
|
||||
if (is_array($act->obj)) {
|
||||
$content = self::get_content($act->obj);
|
||||
}
|
||||
|
||||
$s['parent_mid'] = $act->parent_id;
|
||||
|
||||
@@ -2215,23 +2175,8 @@ class Activity {
|
||||
|
||||
$response_activity = true;
|
||||
|
||||
$s['mid'] = $act->id;
|
||||
$s['uuid'] = ((!empty($act->data['diaspora:guid'])) ? $act->data['diaspora:guid'] : uuid_from_url($s['mid']));
|
||||
|
||||
$s['parent_mid'] = $act->objprop('id') ?: $act->obj;
|
||||
|
||||
/*
|
||||
if ($act->objprop('inReplyTo')) {
|
||||
$s['parent_mid'] = $act->objprop('inReplyTo');
|
||||
}
|
||||
|
||||
$s['thr_parent'] = $act->objprop('id') ?: $act->obj;
|
||||
|
||||
if (empty($s['parent_mid']) || empty($s['thr_parent'])) {
|
||||
logger('response activity without parent_mid or thr_parent');
|
||||
return;
|
||||
}
|
||||
*/
|
||||
// over-ride the object timestamp with the activity
|
||||
|
||||
if (isset($act->data['published'])) {
|
||||
@@ -2242,9 +2187,9 @@ class Activity {
|
||||
$s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']);
|
||||
}
|
||||
|
||||
$obj_actor = $act->objprop('actor') ?: $act->get_actor('attributedTo', $act->obj);
|
||||
$obj_actor = is_array($act->objprop('actor')) ? $act->objprop('actor') : $act->get_actor('attributedTo', $act->obj);
|
||||
|
||||
if (!isset($obj_actor['id'])) {
|
||||
if (empty($obj_actor['id'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2280,12 +2225,8 @@ class Activity {
|
||||
$content['content'] = sprintf(t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']);
|
||||
}
|
||||
|
||||
// TODO: Deprecated
|
||||
if ($act->type === 'emojiReaction') {
|
||||
$content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';');
|
||||
}
|
||||
|
||||
if (in_array($act->type, ['EmojiReact'])) {
|
||||
|
||||
// Pleroma reactions
|
||||
$t = trim(self::get_textfield($act->data, 'content'));
|
||||
|
||||
@@ -2335,10 +2276,15 @@ class Activity {
|
||||
if (!array_key_exists('edited', $s))
|
||||
$s['edited'] = $s['created'];
|
||||
|
||||
$s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content, 'name'));
|
||||
$s['summary'] = self::bb_content($content, 'summary');
|
||||
$s['title'] = (($response_activity) ? EMPTY_STR : html2plain($content['name']));
|
||||
$s['summary'] = (($content['summary'] !== $content['content']) ? html2plain($content['summary']) : '');
|
||||
$s['body'] = ((self::bb_content($content, 'bbcode') && (!$response_activity)) ? self::bb_content($content, 'bbcode') : self::bb_content($content, 'content'));
|
||||
|
||||
// peertube quirks
|
||||
if ($act->objprop('mediaType') === 'text/markdown') {
|
||||
$s['body'] = markdown_to_bb($act->objprop('content'));
|
||||
}
|
||||
|
||||
if ($act->objprop('quoteUrl')) {
|
||||
$quote_bbcode = self::get_quote_bbcode($act->obj['quoteUrl']);
|
||||
|
||||
@@ -2470,7 +2416,8 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
$tag = (($poster) ? '[video poster="' . $poster . '"]' : '[video]' );
|
||||
$tag = (($poster) ? '[video poster=\'' . $poster . '\']' : '[video]' );
|
||||
|
||||
$ptr = null;
|
||||
|
||||
if ($act->objprop('url')) {
|
||||
@@ -2780,7 +2727,7 @@ class Activity {
|
||||
|
||||
$relay = $channel['channel_hash'] === $parent[0]['owner_xchan'];
|
||||
|
||||
if (str_contains($parent[0]['tgt_type'], 'Collection') && !$relay && !$isCollectionOperation) {
|
||||
if (str_contains($parent[0]['tgt_type'], 'Collection') && !$relay && !$is_collection_operation) {
|
||||
logger('not a collection activity');
|
||||
return;
|
||||
}
|
||||
@@ -2974,7 +2921,10 @@ class Activity {
|
||||
// This isn't perfect but the best we can do for now.
|
||||
$item['comment_policy'] = ((isset($act->data['commentPolicy'])) ? $act->data['commentPolicy'] : 'authenticated');
|
||||
|
||||
if (!empty($act->obj['context'])) {
|
||||
if (!empty($act->obj['contextHistory'])) {
|
||||
IConfig::Set($item, 'activitypub', 'context', $act->obj['contextHistory'], 1);
|
||||
}
|
||||
elseif (!empty($act->obj['context'])) {
|
||||
IConfig::Set($item, 'activitypub', 'context', $act->obj['context'], 1);
|
||||
}
|
||||
|
||||
@@ -3009,7 +2959,7 @@ class Activity {
|
||||
|
||||
if (intval($parent[0]['item_private']) === 0) {
|
||||
if (intval($item['item_private'])) {
|
||||
$item['item_restrict'] = $item['item_restrict'] | 1;
|
||||
$item['item_restrict'] = ((isset($item['item_restrict'])) ? $item['item_restrict'] | 1 : 1);
|
||||
$item['allow_cid'] = '<' . $channel['channel_hash'] . '>';
|
||||
$item['allow_gid'] = $item['deny_cid'] = $item['deny_gid'] = '';
|
||||
}
|
||||
@@ -3026,7 +2976,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (isset($item['term']) && !PConfig::Get($channel['channel_id'], 'system', 'no_smilies')) {
|
||||
foreach ($item['term'] as $t) {
|
||||
if ($t['ttype'] === TERM_EMOJI) {
|
||||
@@ -3040,6 +2990,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: not implemented
|
||||
// self::rewrite_mentions($item);
|
||||
@@ -3063,8 +3014,7 @@ class Activity {
|
||||
}
|
||||
|
||||
if ($x['success']) {
|
||||
|
||||
if ($relay && $channel['channel_hash'] === $x['item']['owner_xchan'] && $x['item']['verb'] !== 'Add' && !$isCollectionOperation) {
|
||||
if ($relay && $channel['channel_hash'] === $x['item']['owner_xchan'] && $x['item']['verb'] !== 'Add' && !$is_collection_operation) {
|
||||
$approval = Activity::addToCollection($channel, $act->data, $x['item']['parent_mid'], $x['item'], deliver: false);
|
||||
}
|
||||
|
||||
@@ -3082,13 +3032,8 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
$r = q("select * from item where id = %d limit 1",
|
||||
intval($x['item_id'])
|
||||
);
|
||||
send_status_notifications($x['item_id'], $x['item']);
|
||||
|
||||
if ($r) {
|
||||
send_status_notifications($x['item_id'], $r[0]);
|
||||
}
|
||||
sync_an_item($channel['channel_id'], $x['item_id']);
|
||||
}
|
||||
|
||||
@@ -3405,10 +3350,10 @@ class Activity {
|
||||
if (array_key_exists('startTime', $act) && strpos($act['startTime'], -1, 1) === 'Z') {
|
||||
$adjust = true;
|
||||
$event['adjust'] = 1;
|
||||
$event['dtstart'] = datetime_convert('UTC', 'UTC', $event['startTime'] . (($adjust) ? '' : 'Z'));
|
||||
$event['dtstart'] = datetime_convert('UTC', 'UTC', $act['startTime'] . (($adjust) ? '' : 'Z'));
|
||||
}
|
||||
if (array_key_exists('endTime', $act)) {
|
||||
$event['dtend'] = datetime_convert('UTC', 'UTC', $event['endTime'] . (($adjust) ? '' : 'Z'));
|
||||
$event['dtend'] = datetime_convert('UTC', 'UTC', $act['endTime'] . (($adjust) ? '' : 'Z'));
|
||||
}
|
||||
else {
|
||||
$event['nofinish'] = true;
|
||||
@@ -3607,12 +3552,22 @@ class Activity {
|
||||
}
|
||||
|
||||
foreach ($actor['tag'] as $t) {
|
||||
// TODO: implement FEP-fb2a at the sending side and deprecate PropertyValue
|
||||
if ((isset($t['type']) && $t['type'] === 'PropertyValue') &&
|
||||
(isset($t['name']) && $t['name'] === 'Protocol') &&
|
||||
(isset($t['value']) && in_array($t['value'], ['zot6', 'activitypub', 'diaspora']))
|
||||
isset($t['value'])
|
||||
) {
|
||||
$ret[] = $t['value'];
|
||||
$ret[] = trim($t['value']);
|
||||
}
|
||||
|
||||
// FEP-fb2a - actor metadata
|
||||
if ((isset($t['type']) && $t['type'] === 'Note') &&
|
||||
(isset($t['name']) && $t['name'] === 'Protocols') &&
|
||||
isset($t['content'])
|
||||
) {
|
||||
$ret = array_map('trim', explode(',', $t['content']));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $ret;
|
||||
@@ -3694,6 +3649,8 @@ class Activity {
|
||||
|
||||
return [
|
||||
'zot' => z_root() . '/apschema#',
|
||||
|
||||
'contextHistory' => 'https://w3id.org/fep/171b/contextHistory',
|
||||
'schema' => 'http://schema.org#',
|
||||
'ostatus' => 'http://ostatus.org#',
|
||||
'diaspora' => 'https://diasporafoundation.org/ns/',
|
||||
@@ -3717,7 +3674,6 @@ class Activity {
|
||||
|
||||
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
|
||||
'Hashtag' => 'as:Hashtag'
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
@@ -3868,4 +3824,39 @@ class Activity {
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves message ID from activity object.
|
||||
* @param object $act Activity object
|
||||
* @return string Message ID or empty string if not found
|
||||
*/
|
||||
public static function getMessageID($act): string
|
||||
{
|
||||
if (ActivityStreams::is_response_activity($act->type) || $act->objprop('type') === 'Profile') {
|
||||
return $act->id;
|
||||
}
|
||||
|
||||
return $act->objprop('id', null)
|
||||
?? (is_string($act->obj) ? $act->obj : null)
|
||||
?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves the UUID from an activity object.
|
||||
* @param object $act Activity object
|
||||
* @return string UUID or empty string if not found
|
||||
*/
|
||||
public static function getUUID($act): string
|
||||
{
|
||||
if (ActivityStreams::is_response_activity($act->type)) {
|
||||
return $act->data['uuid']
|
||||
?? $act->data['diaspora:guid']
|
||||
?? '';
|
||||
}
|
||||
|
||||
return $act->objprop('uuid', null)
|
||||
?? $act->objprop('diaspora:guid', null)
|
||||
?? '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -528,49 +528,59 @@ class ActivityStreams {
|
||||
}
|
||||
|
||||
public function checkEddsaSignature() {
|
||||
$publicKey = null;
|
||||
$signer = $this->get_property_obj('verificationMethod', $this->sig);
|
||||
|
||||
$parseUrl = parse_url($signer);
|
||||
|
||||
if (isset($parseUrl['fragment'])) {
|
||||
if (str_starts_with($parseUrl['fragment'], 'z6Mk')) {
|
||||
$publicKey = $parseUrl['fragment'];
|
||||
}
|
||||
unset($parseUrl['fragment']);
|
||||
}
|
||||
|
||||
if (isset($parseUrl['query'])) {
|
||||
unset($parseUrl['query']);
|
||||
}
|
||||
|
||||
$url = unparse_url($parseUrl);
|
||||
|
||||
$hublocs = Activity::get_actor_hublocs($url);
|
||||
|
||||
$hasStoredKey = false;
|
||||
if ($hublocs) {
|
||||
foreach ($hublocs as $hubloc) {
|
||||
if ($publicKey && $hubloc['xchan_epubkey'] === $publicKey) {
|
||||
$hasStoredKey = true;
|
||||
break;
|
||||
}
|
||||
if ($signer && str_starts_with($signer, 'did:key:')) {
|
||||
$publicKey = str_replace('did:key:', '', $signer);
|
||||
$this->signer = ['id' => $signer];
|
||||
if (strpos($publicKey, '#') !== false) {
|
||||
$publicKey = substr($publicKey,0, strpos($publicKey, '#'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$parseUrl = parse_url($signer);
|
||||
|
||||
if (!$hasStoredKey) {
|
||||
$this->signer = Activity::get_actor($url);
|
||||
|
||||
if (isset($this->signer['assertionMethod'])) {
|
||||
if (!isset($this->signer['assertionMethod'][0])) {
|
||||
$this->signer['assertionMethod'] = [$this->signer['assertionMethod']];
|
||||
if (isset($parseUrl['fragment'])) {
|
||||
if (str_starts_with($parseUrl['fragment'], 'z6Mk')) {
|
||||
$publicKey = $parseUrl['fragment'];
|
||||
}
|
||||
unset($parseUrl['fragment']);
|
||||
}
|
||||
|
||||
foreach($this->signer['assertionMethod'] as $am) {
|
||||
if ($url === $am['controller'] &&
|
||||
$am['type'] === 'Multikey' &&
|
||||
str_starts_with($am['publicKeyMultibase'], 'z6Mk')
|
||||
) {
|
||||
$publicKey = $am['publicKeyMultibase'];
|
||||
if (isset($parseUrl['query'])) {
|
||||
unset($parseUrl['query']);
|
||||
}
|
||||
|
||||
$url = unparse_url($parseUrl);
|
||||
|
||||
$hublocs = Activity::get_actor_hublocs($url);
|
||||
|
||||
$hasStoredKey = false;
|
||||
if ($hublocs) {
|
||||
foreach ($hublocs as $hubloc) {
|
||||
if ($publicKey && $hubloc['xchan_epubkey'] === $publicKey) {
|
||||
$hasStoredKey = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$hasStoredKey) {
|
||||
$this->signer = Activity::get_actor($url);
|
||||
|
||||
if (isset($this->signer['assertionMethod'])) {
|
||||
if (!isset($this->signer['assertionMethod'][0])) {
|
||||
$this->signer['assertionMethod'] = [$this->signer['assertionMethod']];
|
||||
}
|
||||
|
||||
foreach($this->signer['assertionMethod'] as $am) {
|
||||
if ($url === $am['controller'] &&
|
||||
$am['type'] === 'Multikey' &&
|
||||
str_starts_with($am['publicKeyMultibase'], 'z6Mk')
|
||||
) {
|
||||
$publicKey = $am['publicKeyMultibase'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ class Apps {
|
||||
'Suggest Channels' => t('Suggest Channels'),
|
||||
'Login' => t('Login'),
|
||||
'Channel Manager' => t('Channel Manager'),
|
||||
'Network' => t('Stream'),
|
||||
'Network' => t('Network'),
|
||||
'Settings' => t('Settings'),
|
||||
'Files' => t('Files'),
|
||||
'Webpages' => t('Webpages'),
|
||||
|
||||
@@ -24,10 +24,16 @@ class Connect {
|
||||
|
||||
$uid = $channel['channel_id'];
|
||||
|
||||
if (strpos($url,'@') === false && strpos($url,'/') === false) {
|
||||
// If we get just a channel name and it is not an URL turn it into a local webbie
|
||||
if (!str_contains($url, '@') && strpos($url,'/') === false) {
|
||||
$url = $url . '@' . App::get_hostname();
|
||||
}
|
||||
|
||||
// Remove a possible leading @
|
||||
if (str_starts_with($url, '@')) {
|
||||
$url = ltrim($url, '@');
|
||||
}
|
||||
|
||||
$result = [ 'success' => false, 'message' => '' ];
|
||||
|
||||
$my_perms = false;
|
||||
|
||||
@@ -35,7 +35,7 @@ class DReport {
|
||||
}
|
||||
|
||||
function addto_update($status) {
|
||||
$this->status = $this->status . ' ' . $status;
|
||||
$this->status = $this->status . ', ' . $status;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,8 +89,14 @@ class DReport {
|
||||
if(array_key_exists('reject',$dr) && intval($dr['reject']))
|
||||
return false;
|
||||
|
||||
if(! ($dr['sender']))
|
||||
if (!$dr['sender']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// do not store dismissed create activities
|
||||
if ($dr['status'] === 'not a collection activity') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is the sender one of our channels?
|
||||
|
||||
|
||||
@@ -95,8 +95,8 @@ class Enotify {
|
||||
if (array_key_exists('verb', $params['item'])) {
|
||||
// localize_item() alters the original item so make a copy first
|
||||
$i = $params['item'];
|
||||
logger('calling localize');
|
||||
localize_item($i);
|
||||
// logger('calling localize');
|
||||
// localize_item($i);
|
||||
$title = $i['title'];
|
||||
$body = $i['body'];
|
||||
$private = (($i['item_private']) || intval($i['item_obscured']));
|
||||
@@ -131,9 +131,9 @@ class Enotify {
|
||||
logger('notification: mail');
|
||||
$subject = sprintf( t('[$Projectname:Notify] New direct message received at %s'), $sitename);
|
||||
|
||||
$preamble = sprintf( t('%1$s sent you a new direct message at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$preamble = sprintf( t('%1$s sent you a new private message at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s sent you %2$s.'), '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', '[zrl=$itemlink]' . t('a direct message') . '[/zrl]');
|
||||
$sitelink = t('Please visit %s to view and/or reply to your direct messages.');
|
||||
$sitelink = t('Please visit %s to view and/or reply to your private messages.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl . '/hq/' . gen_link_id($params['item']['mid']));
|
||||
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/hq/' . gen_link_id($params['item']['mid']) . '">' . $sitename . '</a>');
|
||||
$itemlink = $siteurl . '/hq/' . gen_link_id($params['item']['mid']);
|
||||
@@ -146,7 +146,7 @@ class Enotify {
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
$action = (($moderated) ? t('requested to comment on') : t('commented on'));
|
||||
$action = (($moderated) ? t('requested to post in') : t('posted in'));
|
||||
|
||||
if(array_key_exists('item',$params)) {
|
||||
|
||||
@@ -164,8 +164,8 @@ class Enotify {
|
||||
if(activity_match($params['verb'], ['Dislike', ACTIVITY_DISLIKE]))
|
||||
$action = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_SHARE))
|
||||
$action = t('repeated');
|
||||
if(activity_match($params['verb'], [ACTIVITY_SHARE]))
|
||||
$action = (($moderated) ? t('requested to repeat') : t('repeated'));
|
||||
|
||||
}
|
||||
|
||||
@@ -213,28 +213,36 @@ class Enotify {
|
||||
//$possess_desc = str_replace('<!item_type!>',$possess_desc);
|
||||
|
||||
// "a post"
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
|
||||
// "George Bull's post"
|
||||
if($p)
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
|
||||
if($p) {
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$p[0]['author']['xchan_name'],
|
||||
$item_post_type);
|
||||
$parent_item['author']['xchan_name'],
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
if ($parent_item['owner']['xchan_hash'] === $recip['channel_hash'] && intval($parent_item['item_wall'])) {
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
|
||||
// Some mail softwares relies on subject field for threading.
|
||||
// So, we cannot have different subjects for notifications of the same thread.
|
||||
@@ -263,7 +271,7 @@ class Enotify {
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]))) {
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE, 'Announce']))) {
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
pop_lang();
|
||||
@@ -308,7 +316,6 @@ class Enotify {
|
||||
$item_post_type = item_post_type($p[0]);
|
||||
// $private = $p[0]['item_private'];
|
||||
$parent_id = $p[0]['id'];
|
||||
|
||||
$parent_item = $p[0];
|
||||
|
||||
//$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked'));
|
||||
@@ -320,14 +327,18 @@ class Enotify {
|
||||
if(activity_match($params['item']['verb'], ['Dislike', ACTIVITY_DISLIKE]))
|
||||
$verb = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
if(activity_match($params['item']['verb'], [ACTIVITY_SHARE]))
|
||||
$verb = (($moderated) ? t('requested to repeat') : t('repeated'));
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] === $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
if ($parent_item['author']['xchan_hash'] === $recip['channel_hash']) {
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$verb,
|
||||
$itemlink,
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
else {
|
||||
pop_lang();
|
||||
return;
|
||||
@@ -500,9 +511,14 @@ class Enotify {
|
||||
*/
|
||||
|
||||
|
||||
$hash = ((in_array($params['verb'], ['Create', 'Update'])) ? $params['item']['uuid'] : $params['item']['thr_parent_uuid']);
|
||||
|
||||
if (!$hash) {
|
||||
$hash = new_uuid();
|
||||
}
|
||||
|
||||
$datarray = [];
|
||||
$datarray['hash'] = $params['item']['uuid'] ?? new_uuid();
|
||||
$datarray['hash'] = $hash;
|
||||
$datarray['sender_hash'] = $sender['xchan_hash'];
|
||||
$datarray['xname'] = $sender['xchan_name'];
|
||||
$datarray['url'] = $sender['xchan_url'];
|
||||
@@ -561,8 +577,9 @@ class Enotify {
|
||||
dbesc($datarray['otype'])
|
||||
);
|
||||
|
||||
$r = q("select id from notify where hash = '%s' and ntype = %d and uid = %d limit 1",
|
||||
$r = q("select id from notify where hash = '%s' and link = '%s' and ntype = %d and uid = %d limit 1",
|
||||
dbesc($datarray['hash']),
|
||||
dbesc($itemlink),
|
||||
intval($datarray['ntype']),
|
||||
intval($recip['channel_id'])
|
||||
);
|
||||
@@ -840,8 +857,8 @@ class Enotify {
|
||||
}
|
||||
else {
|
||||
$itemem_text = (($item['item_thread_top'])
|
||||
? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
? (($item['obj_type'] === 'Question') ? t('started a poll') : t('started a conversation'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('posted in %s\'s conversation'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
);
|
||||
|
||||
if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
|
||||
@@ -853,12 +870,7 @@ class Enotify {
|
||||
|
||||
if($item['edited'] > $item['created']) {
|
||||
$edit = true;
|
||||
if($item['item_thread_top']) {
|
||||
$itemem_text = sprintf( t('edited a post dated %s'), relative_date($item['created']));
|
||||
}
|
||||
else {
|
||||
$itemem_text = sprintf( t('edited a comment dated %s'), relative_date($item['created']));
|
||||
}
|
||||
$itemem_text = sprintf( t('edited a message dated %s'), relative_date($item['created']));
|
||||
}
|
||||
|
||||
|
||||
@@ -878,7 +890,7 @@ class Enotify {
|
||||
'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
|
||||
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
|
||||
// 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''),
|
||||
'b64mid' => (($item['uuid']) ? $item['uuid'] : ''),
|
||||
'b64mid' => ((in_array($item['verb'] , ['Like', 'Dislike', 'Announce']) && !empty($item['thr_parent_uuid'])) ? $item['thr_parent_uuid'] : $item['uuid'] ?? ''),
|
||||
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])),
|
||||
'thread_top' => (($item['item_thread_top']) ? true : false),
|
||||
'message' => bbcode(escape_tags($itemem_text)),
|
||||
@@ -898,14 +910,13 @@ class Enotify {
|
||||
}
|
||||
|
||||
static public function format_notify($tt) {
|
||||
|
||||
$message = trim(strip_tags(bbcode($tt['msg'])));
|
||||
|
||||
if(strpos($message, $tt['xname']) === 0)
|
||||
$message = substr($message, strlen($tt['xname']) + 1);
|
||||
|
||||
$x = [
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['link'] : z_root() . '/notify/view/' . $tt['id']),
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_INTRO) ? z_root() . '/notify/view/' . $tt['id'] : $tt['link']),
|
||||
'name' => $tt['xname'],
|
||||
'url' => $tt['url'],
|
||||
'photo' => $tt['photo'],
|
||||
@@ -917,11 +928,9 @@ class Enotify {
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_intros($rr) {
|
||||
|
||||
return [
|
||||
'notify_link' => z_root() . '/connections#' . $rr['abook_id'],
|
||||
'name' => $rr['xchan_name'],
|
||||
|
||||
@@ -13,6 +13,7 @@ class IConfig {
|
||||
static public function Get(&$item, $family, $key, $default = false) {
|
||||
|
||||
$is_item = false;
|
||||
$iid = null;
|
||||
|
||||
if(is_array($item)) {
|
||||
$is_item = true;
|
||||
@@ -27,12 +28,13 @@ class IConfig {
|
||||
elseif(intval($item))
|
||||
$iid = $item;
|
||||
|
||||
if(! $iid)
|
||||
if (!$iid)
|
||||
return $default;
|
||||
|
||||
|
||||
if(is_array($item) && array_key_exists('iconfig',$item) && is_array($item['iconfig'])) {
|
||||
foreach($item['iconfig'] as $c) {
|
||||
if($c['iid'] == $iid && $c['cat'] == $family && $c['k'] == $key)
|
||||
if (isset($c['iid']) && $c['iid'] == $iid && isset($c['cat']) && $c['cat'] == $family && isset($c['k']) && $c['k'] == $key)
|
||||
return $c['v'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,28 @@ use StephenHill\Base58;
|
||||
|
||||
class JcsEddsa2022 {
|
||||
|
||||
public function __construct() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign arbitrary data with the keys of the provided channel.
|
||||
*
|
||||
* @param $data The data to be signed.
|
||||
* @param array $channel A channel as an array of key/value pairs.
|
||||
*
|
||||
* @return An array with the following fields:
|
||||
* - `type`: The type of signature, always `DataIntegrityProof`.
|
||||
* - `cryptosuite`: The cryptographic algorithm used, always `eddsa-jcs-2022`.
|
||||
* - `created`: The UTC date and timestamp when the signature was created.
|
||||
* - `verificationMethod`: The channel URL and the public key separated by a `#`.
|
||||
* - `proofPurpose`: The purpose of the signature, always `assertionMethod`.
|
||||
* - `proofValue`: The signature itself.
|
||||
*
|
||||
* @throws JcsEddsa2022SignatureException if the channel is missing, or
|
||||
* don't have valid keys.
|
||||
*/
|
||||
public function sign($data, $channel): array {
|
||||
if (!is_array($channel) || !isset($channel['channel_epubkey'], $channel['channel_eprvkey'])) {
|
||||
throw new JcsEddsa2022SignException('Invalid or missing channel provided.');
|
||||
}
|
||||
|
||||
$base58 = new Base58();
|
||||
$pubkey = (new Multibase())->publicKey($channel['channel_epubkey']);
|
||||
$options = [
|
||||
|
||||
15
Zotlabs/Lib/JcsEddsa2022SignException.php
Normal file
15
Zotlabs/Lib/JcsEddsa2022SignException.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class JcsEddsa2022SignException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib3\Crypt\PublicKeyLoader;
|
||||
use phpseclib3\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* Keyutils
|
||||
@@ -16,41 +16,42 @@ class Keyutils {
|
||||
* @param string $e exponent
|
||||
* @return string
|
||||
*/
|
||||
public static function meToPem($m, $e) {
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey([
|
||||
public static function meToPem(string $m, string $e): string
|
||||
{
|
||||
$parsedKey = PublicKeyLoader::load([
|
||||
'e' => new BigInteger($e, 256),
|
||||
'n' => new BigInteger($m, 256)
|
||||
]);
|
||||
return $rsa->getPublicKey();
|
||||
|
||||
if (method_exists($parsedKey, 'getPublicKey')) {
|
||||
$parsedKey = $parsedKey->getPublicKey();
|
||||
}
|
||||
return $parsedKey->toString('PKCS8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string key
|
||||
* @return string
|
||||
*/
|
||||
public static function rsaToPem($key) {
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setPublicKey($key);
|
||||
|
||||
return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS8);
|
||||
|
||||
public static function rsaToPem(string $key): string
|
||||
{
|
||||
$parsedKey = PublicKeyLoader::load($key);
|
||||
if (method_exists($parsedKey, 'getPublicKey')) {
|
||||
$parsedKey = $parsedKey->getPublicKey();
|
||||
}
|
||||
return $parsedKey->toString('PKCS8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string key
|
||||
* @return string
|
||||
*/
|
||||
public static function pemToRsa($key) {
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setPublicKey($key);
|
||||
|
||||
return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
|
||||
|
||||
public static function pemToRsa(string $key): string
|
||||
{
|
||||
$parsedKey = PublicKeyLoader::load($key);
|
||||
if (method_exists($parsedKey, 'getPublicKey')) {
|
||||
$parsedKey = $parsedKey->getPublicKey();
|
||||
}
|
||||
return $parsedKey->toString('PKCS1');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,23 +59,28 @@ class Keyutils {
|
||||
* @param string $m reference modulo
|
||||
* @param string $e reference exponent
|
||||
*/
|
||||
public static function pemToMe($key, &$m, &$e) {
|
||||
public static function pemToMe(string $key): array
|
||||
{
|
||||
$parsedKey = PublicKeyLoader::load($key);
|
||||
if (method_exists($parsedKey, 'getPublicKey')) {
|
||||
$parsedKey = $parsedKey->getPublicKey();
|
||||
}
|
||||
$raw = $parsedKey->toString('Raw');
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey($key);
|
||||
$rsa->setPublicKey();
|
||||
|
||||
$m = $rsa->modulus->toBytes();
|
||||
$e = $rsa->exponent->toBytes();
|
||||
$m = $raw['n'];
|
||||
$e = $raw['e'];
|
||||
|
||||
return [$m->toBytes(), $e->toBytes()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pubkey
|
||||
* @return string
|
||||
*/
|
||||
public static function salmonKey($pubkey) {
|
||||
self::pemToMe($pubkey, $m, $e);
|
||||
public static function salmonKey(string $pubkey): string
|
||||
{
|
||||
[$m, $e] = self::pemToMe($pubkey);
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true);
|
||||
}
|
||||
|
||||
@@ -82,11 +88,13 @@ class Keyutils {
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
public static function convertSalmonKey($key) {
|
||||
if (strstr($key, ','))
|
||||
public static function convertSalmonKey(string $key): string
|
||||
{
|
||||
if (str_contains($key, ',')) {
|
||||
$rawkey = substr($key, strpos($key, ',') + 1);
|
||||
else
|
||||
} else {
|
||||
$rawkey = substr($key, 5);
|
||||
}
|
||||
|
||||
$key_info = explode('.', $rawkey);
|
||||
|
||||
@@ -96,4 +104,4 @@ class Keyutils {
|
||||
return self::meToPem($m, $e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,6 +655,11 @@ class Libzot {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if (empty($arr['primary_location']['address'])) {
|
||||
logger('Empty primary location address: ' . print_r($arr, true), LOGGER_DEBUG);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hooks import_xchan
|
||||
* Called when processing the result of zot_finger() to store the result
|
||||
@@ -1164,10 +1169,6 @@ class Libzot {
|
||||
$raw_activity = $AS->data;
|
||||
|
||||
$AS = new ActivityStreams($raw_activity['object'], portable_id: $env['sender']);
|
||||
|
||||
// Store the original activity id and type for later usage
|
||||
$AS->meta['original_id'] = $original_id;
|
||||
$AS->meta['original_type'] = $original_type;
|
||||
}
|
||||
|
||||
if (is_array($AS->obj)) {
|
||||
@@ -1541,6 +1542,7 @@ class Libzot {
|
||||
|
||||
$local_public = $public;
|
||||
$item_result = null;
|
||||
$parent = null;
|
||||
|
||||
$DR = new DReport(z_root(), $sender, $d, $arr['mid'], $arr['uuid']);
|
||||
|
||||
@@ -1556,7 +1558,7 @@ class Libzot {
|
||||
|
||||
$conversation_operation = $is_collection_operation && isset($arr['target']['attributedTo']);
|
||||
|
||||
if (str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
|
||||
if (isset($arr['tgt_type']) && str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
|
||||
$DR->update('not a collection activity');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
@@ -1848,19 +1850,12 @@ class Libzot {
|
||||
dbesc($arr['author_xchan'])
|
||||
);
|
||||
|
||||
// If we import an add/remove activity ($is_collection_operation) we strip off the
|
||||
// add/remove part and only process the object.
|
||||
// When looking up the item to pass it to the notifier for relay, we need to look up
|
||||
// the original (stripped off) message id which we stored in $act->meta.
|
||||
|
||||
$sql_mid = (($is_collection_operation && $relay && $channel['channel_hash'] === $arr['owner_xchan']) ? $act->meta['original_id'] : $arr['mid']);
|
||||
|
||||
// Reactions such as like and dislike could have an mid with /activity/ in it.
|
||||
// Check for both forms in order to prevent duplicates.
|
||||
|
||||
$r = q("select * from item where mid in ('%s', '%s') and uid = %d limit 1",
|
||||
dbesc($sql_mid),
|
||||
dbesc(reverse_activity_mid($sql_mid)),
|
||||
dbesc($arr['mid']),
|
||||
dbesc(reverse_activity_mid($arr['mid'])),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
@@ -2002,7 +1997,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
$DR->addto_update('relayed');
|
||||
$result[] = $DR->get();
|
||||
$result = [$DR->get()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,17 +8,18 @@ class MessageFilter {
|
||||
|
||||
public static function evaluate($item, $incl, $excl) {
|
||||
|
||||
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
|
||||
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
|
||||
$text = prepare_text($item['body'], ((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
|
||||
$text = html2plain((!empty($item['title'])) ? $item['title'] . ' ' . $text : $text);
|
||||
|
||||
$lang = null;
|
||||
|
||||
if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) {
|
||||
$lang = detect_language($text);
|
||||
}
|
||||
|
||||
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
|
||||
|
||||
$until = null;
|
||||
|
||||
// exclude always has priority
|
||||
|
||||
$exclude = (($excl) ? explode("\n", $excl) : null);
|
||||
@@ -41,7 +42,13 @@ class MessageFilter {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
elseif (str_starts_with($word, 'until=')) {
|
||||
$until = strtotime(trim(substr($word, 6)));
|
||||
if ($until > strtotime($item['created'] . ' UTC')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return false;
|
||||
@@ -89,7 +96,13 @@ class MessageFilter {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
elseif (str_starts_with($word, 'until=')) {
|
||||
$until = strtotime(trim(substr($word, 6)));
|
||||
if ($until > strtotime($item['created'] . ' UTC')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return true;
|
||||
@@ -124,9 +137,7 @@ class MessageFilter {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Test for Conditional Execution conditions. Shamelessly ripped off from Code/Render/Comanche
|
||||
*
|
||||
* This is extensible. The first version of variable testing supports tests of the forms:
|
||||
* Evaluate a conditional expression with support for AND (&&) and OR (||) operators.
|
||||
*
|
||||
* - ?foo ~= baz which will check if item.foo contains the string 'baz';
|
||||
* - ?foo == baz which will check if item.foo is the string 'baz';
|
||||
@@ -143,103 +154,110 @@ class MessageFilter {
|
||||
*
|
||||
* The values 0, '', an empty array, and an unset value will all evaluate to false.
|
||||
*
|
||||
* @param string $s
|
||||
* @param array $item
|
||||
* @return bool
|
||||
* @param string $s The condition string to evaluate.
|
||||
* @param array $item The associative array providing variable values.
|
||||
* @return bool True if the condition is met, false otherwise.
|
||||
*/
|
||||
|
||||
public static function test_condition($s,$item) {
|
||||
public static function test_condition($s, $item) {
|
||||
$s = trim($s);
|
||||
|
||||
// Handle OR (||)
|
||||
// Split on '||' not inside quotes
|
||||
$or_parts = preg_split('/\s*\|\|\s*/', $s);
|
||||
if (count($or_parts) > 1) {
|
||||
foreach ($or_parts as $part) {
|
||||
if (self::test_condition(ltrim($part, '?+'), $item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle AND (&&)
|
||||
// Split on '&&' not inside quotes
|
||||
$and_parts = preg_split('/\s*\&\&\s*/', $s);
|
||||
if (count($and_parts) > 1) {
|
||||
foreach ($and_parts as $part) {
|
||||
if (!self::test_condition(ltrim($part, '?+'), $item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Basic checks
|
||||
|
||||
// Contains substring (case-insensitive)
|
||||
if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (stripos($x, trim($matches[2])) !== false) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return (stripos($x, trim($matches[2])) !== false);
|
||||
}
|
||||
|
||||
// Equality
|
||||
if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x == trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x == trim($matches[2]));
|
||||
}
|
||||
|
||||
// Inequality
|
||||
if (preg_match('/(.*?)\s\!\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x != trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x != trim($matches[2]));
|
||||
}
|
||||
|
||||
// Greater than or equal
|
||||
if (preg_match('/(.*?)\s\>\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x >= trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x >= trim($matches[2]));
|
||||
}
|
||||
|
||||
// Less than or equal
|
||||
if (preg_match('/(.*?)\s\<\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x <= trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x <= trim($matches[2]));
|
||||
}
|
||||
|
||||
// Greater than
|
||||
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x > trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x > trim($matches[2]));
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x < trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// Less than
|
||||
if (preg_match('/(.*?)\s\<\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x < trim($matches[2]));
|
||||
}
|
||||
|
||||
if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (is_array($x) && in_array(trim($matches[2]), $x)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// Array contains value
|
||||
if (preg_match('/(.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return (is_array($x) && in_array(trim($matches[2]), $x));
|
||||
}
|
||||
|
||||
// Array contains key
|
||||
if (preg_match('/(.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (is_array($x) && array_key_exists(trim($matches[2]), $x)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return (is_array($x) && array_key_exists(trim($matches[2]), $x));
|
||||
}
|
||||
|
||||
// Ordering of this check (for falsiness) with relation to the following one (check for truthiness) is important.
|
||||
// Falsy check
|
||||
if (preg_match('/\!(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (!$x) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return !$x;
|
||||
}
|
||||
|
||||
// Truthy check (default)
|
||||
if (preg_match('/(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return (bool)$x;
|
||||
}
|
||||
|
||||
// If no conditions matched, return false
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -21,4 +21,13 @@ class Text {
|
||||
return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false);
|
||||
}
|
||||
|
||||
public static function rawurlencode_parts(string $string): string {
|
||||
if (!$string) {
|
||||
return EMPTY_STR;
|
||||
}
|
||||
|
||||
return implode('/', array_map('rawurlencode', explode('/', $string)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Access\AccessList;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once('include/text.php');
|
||||
|
||||
@@ -26,6 +24,7 @@ class ThreadItem {
|
||||
private $parent = null;
|
||||
private $conversation = null;
|
||||
private $redirect_url = null;
|
||||
private $owner_addr = '';
|
||||
private $owner_url = '';
|
||||
private $owner_photo = '';
|
||||
private $owner_name = '';
|
||||
@@ -35,14 +34,12 @@ class ThreadItem {
|
||||
private $channel = null;
|
||||
private $display_mode = 'normal';
|
||||
private $reload = '';
|
||||
private $mid_uuid_map = [];
|
||||
|
||||
|
||||
public function __construct($data) {
|
||||
|
||||
$this->data = $data;
|
||||
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
|
||||
$this->threaded = Config::Get('system','thread_allow');
|
||||
$this->threaded = ((local_channel()) ? PConfig::Get(local_channel(), 'system', 'thread_allow', true) : Config::Get('system', 'thread_allow', true));
|
||||
|
||||
// Prepare the children
|
||||
if(isset($data['children'])) {
|
||||
@@ -65,8 +62,6 @@ class ThreadItem {
|
||||
unset($this->data['children']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// allow a site to configure the order and content of the reaction emoji list
|
||||
if($this->toplevel) {
|
||||
$x = Config::Get('system','reactions');
|
||||
@@ -84,7 +79,7 @@ class ThreadItem {
|
||||
* _ false on failure
|
||||
*/
|
||||
|
||||
public function get_template_data($conv_responses, $mid_uuid_map, $thread_level=1, $conv_flags = []) {
|
||||
public function get_template_data($thread_level=1, $conv_flags = []) {
|
||||
|
||||
$result = [];
|
||||
$item = $this->get_data();
|
||||
@@ -103,6 +98,8 @@ class ThreadItem {
|
||||
$conv = $this->get_conversation();
|
||||
$observer = $conv->get_observer();
|
||||
|
||||
$conv->mid_uuid_map[$item['mid']] = $item['uuid'];
|
||||
|
||||
$acl = new AccessList([]);
|
||||
$acl->set($item);
|
||||
|
||||
@@ -114,7 +111,7 @@ class ThreadItem {
|
||||
$locktype = intval($item['item_private']);
|
||||
|
||||
if ($locktype === 2) {
|
||||
$lock = t('Direct message');
|
||||
$lock = t('Private message');
|
||||
}
|
||||
|
||||
// 0 = limited based on public policy
|
||||
@@ -209,9 +206,9 @@ class ThreadItem {
|
||||
}
|
||||
|
||||
if (in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
|
||||
$response_verbs[] = 'attendyes';
|
||||
$response_verbs[] = 'attendno';
|
||||
$response_verbs[] = 'attendmaybe';
|
||||
$response_verbs[] = 'accept';
|
||||
$response_verbs[] = 'reject';
|
||||
$response_verbs[] = 'tentativeaccept';
|
||||
if($this->is_commentable() && $observer) {
|
||||
$isevent = true;
|
||||
$attend = array( t('I will attend'), t('I will not attend'), t('I might attend'));
|
||||
@@ -222,17 +219,8 @@ class ThreadItem {
|
||||
$response_verbs[] = 'answer';
|
||||
}
|
||||
|
||||
if (!feature_enabled($conv->get_profile_owner(),'dislike')) {
|
||||
unset($conv_responses['dislike']);
|
||||
}
|
||||
|
||||
$responses = get_responses($conv_responses,$response_verbs,$this,$item);
|
||||
|
||||
$my_responses = [];
|
||||
foreach($response_verbs as $v) {
|
||||
$my_responses[$v] = ((isset($conv_responses[$v][$item['mid'] . '-m'])) ? 1 : 0);
|
||||
}
|
||||
|
||||
$response_verbs[] = 'comment';
|
||||
$responses = get_responses($response_verbs, $item);
|
||||
|
||||
/*
|
||||
* We should avoid doing this all the time, but it depends on the conversation mode
|
||||
@@ -242,7 +230,13 @@ class ThreadItem {
|
||||
|
||||
$this->check_wall_to_wall();
|
||||
|
||||
$children = $this->get_children();
|
||||
$children_count = count($children);
|
||||
|
||||
if($this->is_toplevel()) {
|
||||
$conv->comments_total = $responses['comment']['count'] ?? 0;
|
||||
$conv->comments_loaded = $children_count;
|
||||
|
||||
if((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) {
|
||||
$star = [
|
||||
'toggle' => t("Toggle Star Status"),
|
||||
@@ -254,7 +248,6 @@ class ThreadItem {
|
||||
$is_comment = true;
|
||||
}
|
||||
|
||||
|
||||
$verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
|
||||
$forged = ((($item['sig']) && (! intval($item['item_verified']))) ? t('Message signature incorrect') : '');
|
||||
$unverified = '' ; // (($this->is_wall_to_wall() && (! intval($item['item_verified']))) ? t('Message cannot be verified') : '');
|
||||
@@ -287,15 +280,11 @@ class ThreadItem {
|
||||
if((in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) && $conv->get_profile_owner() == local_channel())
|
||||
$has_event = true;
|
||||
|
||||
$like = [];
|
||||
$dislike = [];
|
||||
$reply_to = [];
|
||||
$reactions_allowed = false;
|
||||
|
||||
if($this->is_commentable() && $observer) {
|
||||
$like = array( t("I like this \x28toggle\x29"), t("like"));
|
||||
$dislike = array( t("I don't like this \x28toggle\x29"), t("dislike"));
|
||||
$reply_to = array( t("Reply to this comment"), t("reply"), t("Reply to"));
|
||||
$reply_to = array( t("Reply to this message"), t("reply"), t("Reply to"));
|
||||
$reactions_allowed = true;
|
||||
}
|
||||
|
||||
@@ -339,9 +328,8 @@ class ThreadItem {
|
||||
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
|
||||
|
||||
$comment_count_txt = ['label' => sprintf(tt('%d comment', '%d comments', $total_children), $total_children), 'count' => $total_children];
|
||||
$list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : [];
|
||||
|
||||
$children = $this->get_children();
|
||||
$list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : [];
|
||||
|
||||
$has_tags = (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false);
|
||||
|
||||
@@ -351,14 +339,7 @@ class ThreadItem {
|
||||
|
||||
$midb64 = $item['uuid'];
|
||||
$mids = [ $item['uuid'] ];
|
||||
$response_mids = [];
|
||||
foreach($response_verbs as $v) {
|
||||
if(isset($conv_responses[$v]['mids'][$item['mid']])) {
|
||||
$response_mids = array_merge($response_mids, $conv_responses[$v]['mids'][$item['mid']]);
|
||||
}
|
||||
}
|
||||
|
||||
$mids = array_merge($mids, $response_mids);
|
||||
$json_mids = json_encode($mids);
|
||||
|
||||
// Pinned item processing
|
||||
@@ -372,6 +353,22 @@ class ThreadItem {
|
||||
$contact = App::$contacts[$item['author_xchan']];
|
||||
}
|
||||
|
||||
$blog_mode = $this->get_display_mode() === 'list';
|
||||
$load_more = false;
|
||||
$load_more_title = '';
|
||||
$comments_total_percent = 0;
|
||||
if (($conv->comments_total > $conv->comments_loaded) || ($blog_mode && $conv->comments_total > 3)) {
|
||||
// provide a load more comments button
|
||||
$load_more = true;
|
||||
$load_more_title = sprintf(t('Load the next few of total %d comments'), $conv->comments_total);
|
||||
$comments_total_percent = round(100 * 3 / $conv->comments_total);
|
||||
}
|
||||
|
||||
$expand = '';
|
||||
if ($this->threaded && !empty($item['comment_count'] && !$this->is_toplevel())) {
|
||||
$expand = t('Expand Replies');
|
||||
}
|
||||
|
||||
$tmp_item = array(
|
||||
'template' => $this->get_template(),
|
||||
'mode' => $mode,
|
||||
@@ -384,9 +381,9 @@ class ThreadItem {
|
||||
'folders' => $body['folders'],
|
||||
'text' => strip_tags($body['html']),
|
||||
'id' => $this->get_id(),
|
||||
'parent' => $item['parent'],
|
||||
'mid' => $midb64,
|
||||
'mids' => $json_mids,
|
||||
'parent' => $item['parent'],
|
||||
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
||||
'author_is_group_actor' => (($item['author']['xchan_pubforum']) ? t('Forum') : ''),
|
||||
'isevent' => $isevent,
|
||||
@@ -431,6 +428,7 @@ class ThreadItem {
|
||||
'vote_title' => t('Voting Options'),
|
||||
'is_comment' => $is_comment,
|
||||
'is_new' => $is_new,
|
||||
'owner_addr' => $this->get_owner_addr(),
|
||||
'owner_url' => $this->get_owner_url(),
|
||||
'owner_photo' => $this->get_owner_photo(),
|
||||
'owner_name' => $this->get_owner_name(),
|
||||
@@ -440,13 +438,12 @@ class ThreadItem {
|
||||
'reactions' => $this->reactions,
|
||||
// Item toolbar buttons
|
||||
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
|
||||
'like' => $like,
|
||||
'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
|
||||
'reply_to' => (((! $this->is_toplevel()) && feature_enabled($conv->get_profile_owner(),'reply_to')) ? $reply_to : ''),
|
||||
'reply_to' => ((feature_enabled($conv->get_profile_owner(),'reply_to')) ? $reply_to : ''),
|
||||
'top_hint' => t("Go to previous comment"),
|
||||
'share' => $share,
|
||||
'embed' => $embed,
|
||||
'rawmid' => $item['mid'],
|
||||
'parent_mid' => $item['parent_mid'],
|
||||
'plink' => get_plink($item),
|
||||
'edpost' => $edpost,
|
||||
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts') && ($item['item_type'] == ITEM_TYPE_POST)) ? $star : ''),
|
||||
@@ -466,16 +463,17 @@ class ThreadItem {
|
||||
'list_unseen_txt' => $list_unseen_txt,
|
||||
'markseen' => t('Mark all comments seen'),
|
||||
'responses' => $responses,
|
||||
'my_responses' => $my_responses,
|
||||
// 'my_responses' => $my_responses,
|
||||
'modal_dismiss' => t('Close'),
|
||||
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()),
|
||||
'comment_hidden' => feature_enabled($conv->get_profile_owner(),'reply_to'),
|
||||
'no_comment' => (($item['item_thread_top'] && $item['item_nocomment'])? t('Comments disabled') : ''),
|
||||
'previewing' => ($conv->is_preview() ? true : false ),
|
||||
'preview_lbl' => t('This is an unsaved preview'),
|
||||
'wait' => t('Please wait'),
|
||||
'thread_level' => $thread_level,
|
||||
'settings' => $settings,
|
||||
'thr_parent_uuid' => (($item['parent_mid'] != $item['thr_parent']) ? $mid_uuid_map[$item['thr_parent']] : ''),
|
||||
'thr_parent_uuid' => (($item['parent_mid'] !== $item['thr_parent'] && isset($conv->mid_uuid_map[$item['thr_parent']])) ? $conv->mid_uuid_map[$item['thr_parent']] : ''),
|
||||
'contact_id' => (($contact) ? $contact['abook_id'] : ''),
|
||||
'moderate' => ($item['item_blocked'] == ITEM_MODERATED),
|
||||
'moderate_approve' => t('Approve'),
|
||||
@@ -483,7 +481,25 @@ class ThreadItem {
|
||||
'rtl' => in_array($item['lang'], rtl_languages()),
|
||||
'reactions_allowed' => $reactions_allowed,
|
||||
'reaction_str' => [t('Add yours'), t('Remove yours')],
|
||||
'is_contained' => $this->is_toplevel() && str_contains($item['tgt_type'], 'Collection')
|
||||
'is_contained' => $this->is_toplevel() && str_contains($item['tgt_type'], 'Collection'),
|
||||
'observer_activity' => [
|
||||
'like' => intval($item['observer_like_count'] ?? 0),
|
||||
'dislike' => intval($item['observer_dislike_count'] ?? 0),
|
||||
'announce' => intval($item['observer_announce_count'] ?? 0),
|
||||
'comment' => intval($item['observer_comment_count'] ?? 0),
|
||||
'accept' => intval($item['observer_accept_count'] ?? 0),
|
||||
'reject' => intval($item['observer_reject_count'] ?? 0),
|
||||
'tentativeaccept' => intval($item['observer_tentativeaccept_count'] ?? 0)
|
||||
],
|
||||
'threaded' => $this->threaded,
|
||||
'blog_mode' => $blog_mode,
|
||||
'collapse_comments' => t('show less'),
|
||||
'expand_comments' => $this->threaded ? t('show more') : t('show all'),
|
||||
'load_more' => $load_more,
|
||||
'load_more_title' => $load_more_title,
|
||||
'comments_total' => $conv->comments_total,
|
||||
'comments_total_percent' => $comments_total_percent,
|
||||
'expand' => $expand
|
||||
);
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
@@ -492,25 +508,19 @@ class ThreadItem {
|
||||
$result = $arr['output'];
|
||||
|
||||
$result['children'] = array();
|
||||
$nb_children = count($children);
|
||||
|
||||
$visible_comments = Config::Get('system', 'expanded_comments', 3);
|
||||
$visible_comments = 3; // Config::Get('system', 'expanded_comments', 3);
|
||||
|
||||
if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
|
||||
if(($this->get_display_mode() === 'normal') && ($children_count > 0)) {
|
||||
foreach($children as $child) {
|
||||
$result['children'][] = $child->get_template_data($conv_responses, $mid_uuid_map, $thread_level + 1,$conv_flags);
|
||||
$result['children'][] = $child->get_template_data($thread_level + 1, $conv_flags);
|
||||
}
|
||||
|
||||
// Collapse
|
||||
if(($nb_children > $visible_comments) || ($thread_level > 1)) {
|
||||
if($thread_level === 1 && $children_count > $visible_comments) {
|
||||
$result['children'][0]['comment_firstcollapsed'] = true;
|
||||
$result['children'][0]['num_comments'] = $comment_count_txt['label'];
|
||||
$result['children'][0]['hide_text'] = t('show all');
|
||||
if($thread_level > 1) {
|
||||
$result['children'][$nb_children - 1]['comment_lastcollapsed'] = true;
|
||||
}
|
||||
else {
|
||||
$result['children'][$nb_children - ($visible_comments + 1)]['comment_lastcollapsed'] = true;
|
||||
}
|
||||
$result['children'][$children_count - ($visible_comments + 1)]['comment_lastcollapsed'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,7 +773,7 @@ class ThreadItem {
|
||||
*/
|
||||
private function get_comment_box() {
|
||||
|
||||
if(!$this->is_toplevel() && !Config::Get('system','thread_allow')) {
|
||||
if(!$this->is_toplevel()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -799,10 +809,11 @@ class ThreadItem {
|
||||
'$submit' => t('Submit'),
|
||||
'$edbold' => t('Bold'),
|
||||
'$editalic' => t('Italic'),
|
||||
'$edhighlighter' => t('Highlight selected text'),
|
||||
'$eduline' => t('Underline'),
|
||||
'$edquote' => t('Quote'),
|
||||
'$edcode' => t('Code'),
|
||||
'$edimg' => t('Image'),
|
||||
'$edimg' => t('Embed (existing) photo from your photo albums'),
|
||||
'$edatt' => t('Attach/Upload file'),
|
||||
'$edurl' => t('Insert Link'),
|
||||
'$edvideo' => t('Video'),
|
||||
@@ -833,6 +844,7 @@ class ThreadItem {
|
||||
$conv = $this->get_conversation();
|
||||
$this->wall_to_wall = false;
|
||||
$this->owner_url = '';
|
||||
$this->owner_addr = '';
|
||||
$this->owner_photo = '';
|
||||
$this->owner_name = '';
|
||||
|
||||
@@ -841,12 +853,14 @@ class ThreadItem {
|
||||
|
||||
if($this->is_toplevel() && ($this->get_data_value('author_xchan') != $this->get_data_value('owner_xchan'))) {
|
||||
$this->owner_url = chanlink_hash($this->data['owner']['xchan_hash']);
|
||||
$this->owner_addr = $this->data['owner']['xchan_addr'];
|
||||
$this->owner_photo = $this->data['owner']['xchan_photo_s'];
|
||||
$this->owner_name = $this->data['owner']['xchan_name'];
|
||||
$this->wall_to_wall = true;
|
||||
}
|
||||
elseif($this->is_toplevel() && $this->get_data_value('verb') === 'Announce' && isset($this->data['source'])) {
|
||||
$this->owner_url = chanlink_hash($this->data['source']['xchan_hash']);
|
||||
$this->owner_addr = $this->data['source']['xchan_addr'];
|
||||
$this->owner_photo = $this->data['source']['xchan_photo_s'];
|
||||
$this->owner_name = $this->data['source']['xchan_name'];
|
||||
$this->wall_to_wall = true;
|
||||
@@ -861,6 +875,10 @@ class ThreadItem {
|
||||
return $this->owner_url;
|
||||
}
|
||||
|
||||
private function get_owner_addr() {
|
||||
return $this->owner_addr;
|
||||
}
|
||||
|
||||
private function get_owner_photo() {
|
||||
return $this->owner_photo;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ class ThreadStream {
|
||||
private $prepared_item = '';
|
||||
public $reload = '';
|
||||
private $cipher = 'AES-128-CCM';
|
||||
public $mid_uuid_map = [];
|
||||
public $comments_total = 0;
|
||||
public $comments_loaded = 0;
|
||||
|
||||
|
||||
// $prepared_item is for use by alternate conversation structures such as photos
|
||||
// wherein we've already prepared a top level item which doesn't look anything like
|
||||
@@ -211,16 +215,15 @@ class ThreadStream {
|
||||
* _ The data requested on success
|
||||
* _ false on failure
|
||||
*/
|
||||
public function get_template_data($conv_responses, $mid_uuid_map) {
|
||||
public function get_template_data() {
|
||||
$result = array();
|
||||
|
||||
foreach($this->threads as $item) {
|
||||
|
||||
if(($item->get_data_value('id') == $item->get_data_value('parent')) && $this->prepared_item) {
|
||||
$item_data = $this->prepared_item;
|
||||
}
|
||||
else {
|
||||
$item_data = $item->get_template_data($conv_responses, $mid_uuid_map);
|
||||
$item_data = $item->get_template_data();
|
||||
}
|
||||
if(!$item_data) {
|
||||
logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR);
|
||||
|
||||
@@ -89,7 +89,7 @@ trait HelpHelperTrait {
|
||||
);
|
||||
|
||||
return bbcode(
|
||||
t("This page is not yet available in {$prefered_language_name}. See [observer.baseurl]/help/developer/developer_guide#Translations for information about how to help.")
|
||||
t("This page is not yet available in {$prefered_language_name}. See [observer.baseurl]/help/developer/developers_guide#Translations for information about how to help.")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
|
||||
// logger('mod_acl: ' . print_r($_GET,true),LOGGER_DATA);
|
||||
|
||||
$start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
|
||||
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500);
|
||||
$search = (x($_REQUEST,'search') ? $_REQUEST['search'] : '');
|
||||
$type = (x($_REQUEST,'type') ? $_REQUEST['type'] : '');
|
||||
$noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false);
|
||||
$start = (!empty($_REQUEST['start']) ? $_REQUEST['start'] : 0);
|
||||
$count = (!empty($_REQUEST['count']) ? $_REQUEST['count'] : 500);
|
||||
$search = (!empty($_REQUEST['search']) ? $_REQUEST['search'] : '');
|
||||
$type = (!empty($_REQUEST['type']) ? $_REQUEST['type'] : '');
|
||||
$noforums = (!empty($_REQUEST['n']) ? $_REQUEST['n'] : false);
|
||||
|
||||
|
||||
// $type =
|
||||
@@ -53,7 +53,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
// List of channels whose connections to also suggest,
|
||||
// e.g. currently viewed channel or channels mentioned in a post
|
||||
|
||||
$extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array());
|
||||
$extra_channels = (!empty($_REQUEST['extra_channels']) ? $_REQUEST['extra_channels'] : []);
|
||||
|
||||
// The different autocomplete libraries use different names for the search text
|
||||
// parameter. Internally we'll use $search to represent the search text no matter
|
||||
@@ -416,7 +416,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
$dirmode = intval(Config::Get('system','directory_mode'));
|
||||
$search = ((x($_REQUEST,'search')) ? htmlentities($_REQUEST['search'],ENT_COMPAT,'UTF-8',false) : '');
|
||||
$search = ((!empty($_REQUEST['search'])) ? htmlentities($_REQUEST['search'], ENT_COMPAT, 'UTF-8', false) : '');
|
||||
if(! $search || mb_strlen($search) < 2)
|
||||
return array();
|
||||
|
||||
@@ -446,7 +446,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
|
||||
$token = Config::Get('system','realm_token');
|
||||
|
||||
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
|
||||
$count = (!empty($_REQUEST['count']) ? $_REQUEST['count'] : 100);
|
||||
if($url) {
|
||||
$query = $url . '?f=' . (($token) ? '&t=' . urlencode($token) : '');
|
||||
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
|
||||
|
||||
@@ -23,14 +23,14 @@ class Activity extends Controller {
|
||||
if (! $item_id)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$portable_id = EMPTY_STR;
|
||||
$portable_id = null;
|
||||
|
||||
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
|
||||
dbesc(ACTIVITY_FOLLOW),
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -166,6 +166,7 @@ class Activity extends Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$portable_id = null;
|
||||
$ob_authorize = false;
|
||||
$item_uid = 0;
|
||||
|
||||
@@ -191,7 +192,7 @@ class Activity extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
|
||||
@@ -133,6 +133,11 @@ class Attach_edit extends Controller {
|
||||
}
|
||||
$x = attach_move($channel_id, $resource, $newfolder, (($single) ? $newfilename : ''));
|
||||
|
||||
if (!$x['success']) {
|
||||
notice($x['message'] . EOL);
|
||||
goaway($return_path);
|
||||
}
|
||||
|
||||
$actions_done .= 'move,';
|
||||
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class Channel extends Controller {
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'Digest' => HTTPSig::generate_digest_header($data),
|
||||
'(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']
|
||||
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T')
|
||||
];
|
||||
|
||||
$h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel));
|
||||
@@ -266,7 +266,7 @@ class Channel extends Controller {
|
||||
'default_location' => (($is_owner) ? App::$profile['channel_location'] : ''),
|
||||
'nickname' => App::$profile['channel_address'],
|
||||
'lockstate' => (((strlen(App::$profile['channel_allow_cid'])) || (strlen(App::$profile['channel_allow_gid'])) || (strlen(App::$profile['channel_deny_cid'])) || (strlen(App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'),
|
||||
'acl' => (($is_owner) ? populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''),
|
||||
'acl' => (($is_owner) ? populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'member/permissions') : ''),
|
||||
'permissions' => $channel_acl,
|
||||
'showacl' => (($is_owner) ? 'yes' : ''),
|
||||
'bang' => '',
|
||||
@@ -298,12 +298,15 @@ class Channel extends Controller {
|
||||
|
||||
$item_normal = item_normal();
|
||||
$item_normal_update = item_normal_update();
|
||||
$sql_extra = item_permissions_sql(App::$profile['profile_uid']);
|
||||
$sql_extra = '';
|
||||
$permission_sql = item_permissions_sql(App::$profile['profile_uid']);
|
||||
|
||||
if (feature_enabled(App::$profile['profile_uid'], 'channel_list_mode') && (!$mid))
|
||||
$page_mode = 'client';
|
||||
|
||||
$blog_mode = feature_enabled(App::$profile['profile_uid'], 'channel_list_mode') && !$mid;
|
||||
if ($blog_mode) {
|
||||
$page_mode = 'list';
|
||||
else
|
||||
$page_mode = 'client';
|
||||
}
|
||||
|
||||
$abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " ";
|
||||
|
||||
@@ -334,8 +337,8 @@ class Channel extends Controller {
|
||||
if (($update) && (!$load)) {
|
||||
|
||||
if ($mid) {
|
||||
$r = q("SELECT parent AS item_id, uuid from item where $identifier = '%s' and uid = %d $item_normal_update
|
||||
AND item_wall = 1 $simple_update $sql_extra limit 1",
|
||||
$r = q("SELECT *, parent AS item_id from item where $identifier = '%s' and uid = %d $item_normal_update
|
||||
AND item_wall = 1 $simple_update $permission_sql $sql_extra limit 1",
|
||||
dbesc($mid),
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
@@ -346,6 +349,7 @@ class Channel extends Controller {
|
||||
WHERE uid = %d $item_normal_update
|
||||
AND item_wall = 1 $simple_update
|
||||
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
|
||||
$permission_sql
|
||||
$sql_extra
|
||||
ORDER BY created DESC",
|
||||
intval(App::$profile['profile_uid'])
|
||||
@@ -382,8 +386,8 @@ class Channel extends Controller {
|
||||
|
||||
if ($noscript_content || $load) {
|
||||
if ($mid) {
|
||||
$r = q("SELECT parent AS item_id, uuid from item where $identifier = '%s' and uid = %d $item_normal
|
||||
AND item_wall = 1 $sql_extra limit 1",
|
||||
$r = q("SELECT *, parent AS item_id from item where $identifier = '%s' and uid = %d $item_normal
|
||||
AND item_wall = 1 $permission_sql $sql_extra limit 1",
|
||||
dbesc($mid),
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
@@ -392,13 +396,18 @@ class Channel extends Controller {
|
||||
}
|
||||
}
|
||||
else {
|
||||
$r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item
|
||||
left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids )
|
||||
WHERE true and item.uid = %d $item_normal
|
||||
$r = q("SELECT parent AS item_id, $ordering FROM item
|
||||
LEFT JOIN abook ON (item.author_xchan = abook.abook_xchan $abook_uids)
|
||||
WHERE item.uid = %d
|
||||
AND item.id = item.parent
|
||||
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
|
||||
AND item.item_wall = 1 AND item.item_thread_top = 1
|
||||
$sql_extra $sql_extra2
|
||||
ORDER BY $ordering DESC, item_id $pager_sql ",
|
||||
AND item.item_wall = 1
|
||||
$item_normal
|
||||
$permission_sql
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
ORDER BY $ordering DESC, item_id
|
||||
$pager_sql",
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
}
|
||||
@@ -408,19 +417,15 @@ class Channel extends Controller {
|
||||
}
|
||||
}
|
||||
if ($r) {
|
||||
$parents_str = ids_to_querystr($r, 'item_id');
|
||||
$thr_parents = null;
|
||||
if ($mid) {
|
||||
$thr_parents = get_recursive_thr_parents($r[0]);
|
||||
}
|
||||
|
||||
$r = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE item.uid = %d $item_normal
|
||||
AND item.parent IN ( %s )
|
||||
$sql_extra ",
|
||||
intval(App::$profile['profile_uid']),
|
||||
dbesc($parents_str)
|
||||
);
|
||||
$items = items_by_parent_ids($r, $thr_parents, $permission_sql, $blog_mode);
|
||||
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$items = conv_sort($items, $ordering);
|
||||
|
||||
if ($load && $mid && (!count($items))) {
|
||||
@@ -434,11 +439,8 @@ class Channel extends Controller {
|
||||
$items = [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
$mode = (($search) ? 'search' : 'channel');
|
||||
|
||||
|
||||
if ((!$update) && (!$load)) {
|
||||
|
||||
// This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Zotlabs\Module;
|
||||
* Module for accessing the DAV storage area.
|
||||
*/
|
||||
|
||||
use App;
|
||||
use Sabre\DAV as SDAV;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Storage\BasicAuth;
|
||||
@@ -32,6 +33,15 @@ class Cloud extends Controller {
|
||||
*/
|
||||
function init() {
|
||||
|
||||
// TODO: why is this required?
|
||||
// if we arrived at this path with any query parameters in the url, build a clean url without
|
||||
// them and redirect.
|
||||
|
||||
$parsed = parse_url(App::$query_string);
|
||||
if (!empty($parsed['query'])) {
|
||||
goaway(z_root() . '/' . $parsed['path']);
|
||||
}
|
||||
|
||||
if (! is_dir('store'))
|
||||
os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
|
||||
|
||||
@@ -44,15 +54,13 @@ class Cloud extends Controller {
|
||||
if ($which)
|
||||
profile_load( $which, $profile);
|
||||
|
||||
|
||||
|
||||
$auth = new BasicAuth();
|
||||
|
||||
$ob_hash = get_observer_hash();
|
||||
|
||||
if ($ob_hash) {
|
||||
if (local_channel()) {
|
||||
$channel = \App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
$auth->setCurrentUser($channel['channel_address']);
|
||||
$auth->channel_account_id = $channel['channel_account_id'];
|
||||
$auth->channel_id = $channel['channel_id'];
|
||||
@@ -63,19 +71,12 @@ class Cloud extends Controller {
|
||||
$auth->observer = $ob_hash;
|
||||
}
|
||||
|
||||
// if we arrived at this path with any query parameters in the url, build a clean url without
|
||||
// them and redirect.
|
||||
|
||||
if(! array_key_exists('cloud_sort',$_SESSION)) {
|
||||
$_SESSION['cloud_sort'] = 'name';
|
||||
}
|
||||
|
||||
$_SESSION['cloud_sort'] = ((isset($_REQUEST['sort']) && $_REQUEST['sort']) ? trim(notags($_REQUEST['sort'])) : $_SESSION['cloud_sort']);
|
||||
|
||||
$x = clean_query_string();
|
||||
if($x !== \App::$query_string)
|
||||
goaway(z_root() . '/' . $x);
|
||||
|
||||
$rootDirectory = new Directory('/', [], $auth);
|
||||
|
||||
// A SabreDAV server-object
|
||||
@@ -116,16 +117,16 @@ class Cloud extends Controller {
|
||||
function DAVException($err) {
|
||||
|
||||
if($err instanceof \Sabre\DAV\Exception\NotFound) {
|
||||
\App::$page['content'] = '<h2>404 Not found</h2>';
|
||||
App::$page['content'] = '<h2>404 Not found</h2>';
|
||||
}
|
||||
elseif($err instanceof \Sabre\DAV\Exception\Forbidden) {
|
||||
\App::$page['content'] = '<h2>403 Forbidden</h2>';
|
||||
App::$page['content'] = '<h2>403 Forbidden</h2>';
|
||||
}
|
||||
elseif($err instanceof \Sabre\DAV\Exception\NotImplemented) {
|
||||
goaway(z_root() . '/' . \App::$query_string);
|
||||
goaway(z_root() . '/' . App::$query_string);
|
||||
}
|
||||
else {
|
||||
\App::$page['content'] = '<h2>Unknown error</h2>';
|
||||
App::$page['content'] = '<h2>Unknown error</h2>';
|
||||
}
|
||||
|
||||
construct_page();
|
||||
|
||||
@@ -30,7 +30,7 @@ class Conversation extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -83,9 +83,9 @@ class Conversation extends Controller {
|
||||
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
|
||||
// with a bias towards those items owned by channels on this site (item_wall = 1)
|
||||
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
if (!$i) {
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
|
||||
dbesc($r[0]['parent_mid'])
|
||||
);
|
||||
|
||||
@@ -81,7 +81,7 @@ class Display extends Controller {
|
||||
'default_location' => $channel['channel_location'],
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'member/permissions'),
|
||||
'permissions' => $channel_acl,
|
||||
'bang' => '',
|
||||
'visitor' => true,
|
||||
@@ -212,7 +212,7 @@ class Display extends Controller {
|
||||
$observer_hash = get_observer_hash();
|
||||
$item_normal = item_normal();
|
||||
$item_normal_update = item_normal_update();
|
||||
$sql_extra = '';
|
||||
$permission_sql = '';
|
||||
$r = [];
|
||||
|
||||
if($noscript_content || $load) {
|
||||
@@ -231,7 +231,7 @@ class Display extends Controller {
|
||||
}
|
||||
|
||||
if(!$r) {
|
||||
$sql_extra = item_permissions_sql(0, $observer_hash);
|
||||
$permission_sql = item_permissions_sql(0, $observer_hash);
|
||||
|
||||
$r = q("SELECT item.id AS item_id FROM item
|
||||
WHERE ((mid = '%s'
|
||||
@@ -239,7 +239,7 @@ class Display extends Controller {
|
||||
AND item.deny_gid = '' AND item_private = 0 )
|
||||
AND uid IN ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
|
||||
OR uid = %d ))) OR
|
||||
(mid = '%s' $sql_extra ))
|
||||
(mid = '%s' $permission_sql ))
|
||||
$item_normal
|
||||
limit 1",
|
||||
dbesc($target_item['parent_mid']),
|
||||
@@ -269,7 +269,7 @@ class Display extends Controller {
|
||||
}
|
||||
|
||||
if(!$r) {
|
||||
$sql_extra = item_permissions_sql(0, $observer_hash);
|
||||
$permission_sql = item_permissions_sql(0, $observer_hash);
|
||||
|
||||
$r = q("SELECT item.id as item_id from item
|
||||
WHERE ((parent_mid = '%s'
|
||||
@@ -277,7 +277,7 @@ class Display extends Controller {
|
||||
AND item.deny_gid = '' AND item_private = 0 )
|
||||
and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
|
||||
OR uid = %d ))) OR
|
||||
(parent_mid = '%s' $sql_extra ))
|
||||
(parent_mid = '%s' $permission_sql ))
|
||||
$item_normal
|
||||
limit 1",
|
||||
dbesc($target_item['parent_mid']),
|
||||
@@ -288,17 +288,12 @@ class Display extends Controller {
|
||||
}
|
||||
|
||||
if($r) {
|
||||
$parents_str = ids_to_querystr($r,'item_id');
|
||||
if($parents_str) {
|
||||
$items = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE parent in ( %s ) $sql_extra $item_normal ",
|
||||
dbesc($parents_str)
|
||||
);
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items,true);
|
||||
$items = conv_sort($items,'created');
|
||||
}
|
||||
$thr_parents = get_recursive_thr_parents($target_item);
|
||||
$items = items_by_parent_ids($r, $thr_parents, $permission_sql);
|
||||
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items,true);
|
||||
$items = conv_sort($items,'created');
|
||||
}
|
||||
else {
|
||||
$items = array();
|
||||
|
||||
@@ -43,7 +43,7 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
$arr = explode('/', $href);
|
||||
$resource_id = array_pop($arr);
|
||||
$x = self::photolink($resource_id);
|
||||
if($x)
|
||||
if($x)
|
||||
json_return_and_die(array('status' => true, 'photolink' => $x, 'resource_id' => $resource_id));
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
}
|
||||
@@ -55,7 +55,7 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
$output = EMPTY_STR;
|
||||
if($channel) {
|
||||
$resolution = ((feature_enabled($channel['channel_id'],'large_photos')) ? 1 : 2);
|
||||
$r = q("select mimetype, height, width from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1",
|
||||
$r = q("select mimetype, filename from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1",
|
||||
dbesc($resource),
|
||||
intval($resolution),
|
||||
intval($channel['channel_id'])
|
||||
@@ -63,6 +63,8 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
if(! $r)
|
||||
return $output;
|
||||
|
||||
$filename = $r[0]['filename'];
|
||||
|
||||
if($r[0]['mimetype'] === 'image/jpeg')
|
||||
$ext = '.jpg';
|
||||
elseif($r[0]['mimetype'] === 'image/png')
|
||||
@@ -75,7 +77,7 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
$ext = EMPTY_STR;
|
||||
|
||||
$output = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $resource . ']' .
|
||||
'[zmg=' . $r[0]['width'] . 'x' . $r[0]['height'] . ']' . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . '[/zmg][/zrl]';
|
||||
'[zmg=' . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . ']' . $filename . '[/zmg][/zrl]' . "\r\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
@@ -11,39 +11,42 @@ require_once('include/photos.php');
|
||||
class File_upload extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
logger('file upload: ' . print_r($_REQUEST,true));
|
||||
logger('file upload: ' . print_r($_POST,true));
|
||||
logger('file upload: ' . print_r($_FILES,true));
|
||||
|
||||
$channel = (($_REQUEST['channick']) ? channelx_by_nick($_REQUEST['channick']) : null);
|
||||
$channel = (($_POST['channick']) ? channelx_by_nick($_POST['channick']) : null);
|
||||
|
||||
if(! $channel) {
|
||||
if (!$channel) {
|
||||
logger('channel not found');
|
||||
killme();
|
||||
is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
|
||||
}
|
||||
|
||||
$_REQUEST['source'] = 'file_upload';
|
||||
$_POST['source'] = 'file_upload';
|
||||
|
||||
if($channel['channel_id'] != local_channel()) {
|
||||
$_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']);
|
||||
$_REQUEST['group_allow'] = expand_acl($channel['channel_allow_gid']);
|
||||
$_REQUEST['contact_deny'] = expand_acl($channel['channel_deny_cid']);
|
||||
$_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']);
|
||||
$_POST['contact_allow'] = expand_acl($channel['channel_allow_cid']);
|
||||
$_POST['group_allow'] = expand_acl($channel['channel_allow_gid']);
|
||||
$_POST['contact_deny'] = expand_acl($channel['channel_deny_cid']);
|
||||
$_POST['group_deny'] = expand_acl($channel['channel_deny_gid']);
|
||||
}
|
||||
|
||||
$_REQUEST['allow_cid'] = ((isset($_REQUEST['contact_allow'])) ? perms2str($_REQUEST['contact_allow']) : '');
|
||||
$_REQUEST['allow_gid'] = ((isset($_REQUEST['group_allow'])) ? perms2str($_REQUEST['group_allow']) : '');
|
||||
$_REQUEST['deny_cid'] = ((isset($_REQUEST['contact_deny'])) ? perms2str($_REQUEST['contact_deny']) : '');
|
||||
$_REQUEST['deny_gid'] = ((isset($_REQUEST['group_deny'])) ? perms2str($_REQUEST['group_deny']) : '');
|
||||
$_POST['allow_cid'] = ((isset($_POST['contact_allow'])) ? perms2str($_POST['contact_allow']) : '');
|
||||
$_POST['allow_gid'] = ((isset($_POST['group_allow'])) ? perms2str($_POST['group_allow']) : '');
|
||||
$_POST['deny_cid'] = ((isset($_POST['contact_deny'])) ? perms2str($_POST['contact_deny']) : '');
|
||||
$_POST['deny_gid'] = ((isset($_POST['group_deny'])) ? perms2str($_POST['group_deny']) : '');
|
||||
|
||||
if(isset($_REQUEST['filename']) && strlen($_REQUEST['filename'])) {
|
||||
$r = attach_mkdir($channel, get_observer_hash(), $_REQUEST);
|
||||
if($r['success']) {
|
||||
$hash = $r['data']['hash'];
|
||||
$sync = attach_export_data($channel,$hash);
|
||||
if($sync) {
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
}
|
||||
goaway(z_root() . '/' . $_REQUEST['return_url']);
|
||||
if(isset($_POST['filename']) && strlen($_POST['filename'])) {
|
||||
$r = attach_mkdir($channel, get_observer_hash(), $_POST);
|
||||
|
||||
if (!$r['success']) {
|
||||
notice($r['message'] . EOL);
|
||||
is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
|
||||
}
|
||||
|
||||
$hash = $r['data']['hash'];
|
||||
$sync = attach_export_data($channel,$hash);
|
||||
if ($sync) {
|
||||
Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -90,19 +93,19 @@ class File_upload extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$r = attach_store($channel, get_observer_hash(), '', $_REQUEST);
|
||||
if($r['success']) {
|
||||
$sync = attach_export_data($channel,$r['data']['hash']);
|
||||
if($sync)
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
$r = attach_store($channel, get_observer_hash(), '', $_POST);
|
||||
if (!$r['success']) {
|
||||
notice($r['message'] . EOL);
|
||||
is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
|
||||
}
|
||||
|
||||
$sync = attach_export_data($channel,$r['data']['hash']);
|
||||
if ($sync) {
|
||||
Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
|
||||
}
|
||||
}
|
||||
|
||||
if(is_ajax())
|
||||
killme();
|
||||
|
||||
goaway(z_root() . '/' . $_REQUEST['return_url']);
|
||||
is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class Help extends \Zotlabs\Web\Controller {
|
||||
$this->determine_help_language();
|
||||
|
||||
if (empty($_REQUEST['search']) && argc() === 1) {
|
||||
goaway("/help/about/about");
|
||||
goaway("/help/about");
|
||||
killme();
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class Help extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
|
||||
if(argc() > 2 && argv(argc()-2) === 'assets') {
|
||||
if(argc() > 2 && argv(argc()-2) === 'pic') {
|
||||
$path = '';
|
||||
for($x = 1; $x < argc(); $x ++) {
|
||||
if(strlen($path))
|
||||
|
||||
@@ -24,9 +24,13 @@ class Home extends Controller {
|
||||
$key = Config::Get('system', 'prvkey');
|
||||
$ret = json_encode(Libzot::site_info());
|
||||
|
||||
$headers = ['Content-Type' => 'application/x-zot+json', 'Digest' => HTTPSig::generate_digest_header($ret)];
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$h = HTTPSig::create_sig($headers, $key, z_root());
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'Digest' => HTTPSig::generate_digest_header($ret),
|
||||
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T')
|
||||
];
|
||||
|
||||
$h = HTTPSig::create_sig($headers, $key, z_root());
|
||||
HTTPSig::set_headers($h);
|
||||
|
||||
echo $ret;
|
||||
@@ -68,9 +72,9 @@ class Home extends Controller {
|
||||
|
||||
$o = '';
|
||||
|
||||
if (x($_SESSION, 'theme'))
|
||||
if (isset($_SESSION['theme']))
|
||||
unset($_SESSION['theme']);
|
||||
if (x($_SESSION, 'mobile_theme'))
|
||||
if (isset($_SESSION['mobile_theme']))
|
||||
unset($_SESSION['mobile_theme']);
|
||||
|
||||
$splash = ((argc() > 1 && argv(1) === 'splash') ? true : false);
|
||||
@@ -100,14 +104,25 @@ class Home extends Controller {
|
||||
goaway($frontpage);
|
||||
}
|
||||
|
||||
$o .= '<div class="generic-content-wrapper">';
|
||||
|
||||
$sitename = Config::Get('system', 'sitename');
|
||||
if ($sitename)
|
||||
$o .= '<h1 class="home-welcome">' . sprintf(t('Welcome to %s'), $sitename) . '</h1>';
|
||||
if ($sitename) {
|
||||
$o .= '<div class="section-title-wrapper">';
|
||||
$o .= '<h2 class="">' . sprintf(t('Welcome to %s'), $sitename) . '</h2>';
|
||||
$o .= '</div>';
|
||||
|
||||
}
|
||||
|
||||
$o .= '<div class="section-content-wrapper">';
|
||||
|
||||
$loginbox = Config::Get('system', 'login_on_homepage');
|
||||
if (intval($loginbox) || $loginbox === false)
|
||||
$o .= login(true);
|
||||
|
||||
$o .= '</div>';
|
||||
$o .= '</div>';
|
||||
|
||||
return $o;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Widget\Messages;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Hq extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -50,12 +51,13 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
// select the target item with a bias to our own item
|
||||
$sql_order = ((local_channel() > $sys['channel_id']) ? 'DESC' : 'ASC');
|
||||
|
||||
$r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where uid in (%d, %d) and $identifier = '%s' order by uid $sql_order limit 2",
|
||||
$r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where uid in (%d, %d) and $identifier = '%s' order by uid $sql_order limit 2",
|
||||
intval(local_channel()),
|
||||
intval($sys['channel_id']),
|
||||
dbesc($item_hash)
|
||||
);
|
||||
|
||||
|
||||
if($r) {
|
||||
$target_item = $r[0];
|
||||
if (intval($target_item['uid']) === intval($sys['channel_id'])) {
|
||||
@@ -86,7 +88,7 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
'default_location' => $channel['channel_location'],
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'member/permissions'),
|
||||
'permissions' => $channel_acl,
|
||||
'bang' => '',
|
||||
'visitor' => true,
|
||||
@@ -129,7 +131,7 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
'$nouveau' => '0',
|
||||
'$wall' => '0',
|
||||
'$page' => '1',
|
||||
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
|
||||
'$list' => ((!empty($_REQUEST['list'])) ? intval($_REQUEST['list']) : 0),
|
||||
'$search' => '',
|
||||
'$xchan' => '',
|
||||
'$order' => '',
|
||||
@@ -145,7 +147,6 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($load && $target_item) {
|
||||
|
||||
if (!$sys_item) {
|
||||
$r = q("SELECT item.id AS item_id FROM item
|
||||
WHERE uid = %d
|
||||
@@ -199,11 +200,8 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($r) {
|
||||
$items = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE parent = '%s' $item_normal $sql_extra",
|
||||
dbesc($r[0]['item_id'])
|
||||
);
|
||||
$thr_parents = get_recursive_thr_parents($target_item);
|
||||
$items = items_by_parent_ids($r, $thr_parents);
|
||||
|
||||
xchan_query($items,true,(($sys_item) ? local_channel() : 0));
|
||||
$items = fetch_post_tags($items,true);
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace Zotlabs\Module;
|
||||
*
|
||||
* Controller for responding to x-zot: protocol requests
|
||||
* x-zot:_jkfRG85nJ-714zn-LW_VbTFW8jSjGAhAydOcJzHxqHkvEHWG2E0RbA_pbch-h4R63RG1YJZifaNzgccoLa3MQ/453c1678-1a79-4af7-ab65-6b012f6cab77
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
@@ -104,7 +104,7 @@ class Id extends Controller {
|
||||
$headers['Content-Type'] = 'application/x-zot+json' ;
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
|
||||
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $ret;
|
||||
|
||||
@@ -310,9 +310,9 @@ class Invite extends Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
// zai1
|
||||
$channel_id = local_channel();
|
||||
|
||||
if(! local_channel()) {
|
||||
if ($channel_id === false || $channel_id < 1) {
|
||||
notice( 'ZAI0101E,' . t('Permission denied.') . EOL);
|
||||
return;
|
||||
}
|
||||
@@ -330,15 +330,15 @@ class Invite extends Controller {
|
||||
return $o;
|
||||
}
|
||||
|
||||
// invitation_by_user may still not configured, the default 'na' will tell this
|
||||
// if configured, 0 disables invitations by users, other numbers are how many invites a user may propagate
|
||||
$invuser = Config::Get('system','invitation_by_user', 'na');
|
||||
$ihave = $this->count_invites_by_user($channel_id);
|
||||
|
||||
// if the mortal user drives the invitation
|
||||
If (! is_site_admin()) {
|
||||
|
||||
// when not configured, 4 is the default
|
||||
$invuser = ($invuser === 'na') ? 4 : $invuser;
|
||||
if (is_site_admin()) {
|
||||
// Admins have unlimited invites
|
||||
$invuser = '∞';
|
||||
} else {
|
||||
// invitation_by_user may still not configured, the default 'na' will tell this
|
||||
// if configured, 0 disables invitations by users, other numbers are how many invites a user may propagate
|
||||
$invuser = Config::Get('system','invitation_by_user', 4);
|
||||
|
||||
// a config value 0 disables invitation by users
|
||||
if (!$invuser) {
|
||||
@@ -350,12 +350,6 @@ class Invite extends Controller {
|
||||
notice( 'ZAI0105W,' . t('You have no more invitations available') . EOL);
|
||||
return '';
|
||||
}
|
||||
|
||||
} else {
|
||||
// general deity admin invite limit infinite (theoretical)
|
||||
if ($invuser === 'na') Config::Set('system','invitation_by_user', 4);
|
||||
// for display only
|
||||
$invuser = '∞';
|
||||
}
|
||||
|
||||
// xchan record of the page observer
|
||||
@@ -394,17 +388,6 @@ class Invite extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
if ($wehave > $invmaxau) {
|
||||
if (! is_site_admin()) {
|
||||
$feedbk .= 'ZAI0200E,' . t('All users invitation limit exceeded.') . $eol;
|
||||
}
|
||||
}
|
||||
|
||||
// let see how many invites currently used by the user
|
||||
$r = q("SELECT count(reg_id) AS n FROM register WHERE reg_vital = 1 AND reg_byc = %d",
|
||||
intval(local_channel()));
|
||||
$ihave = $r ? $r[0]['n'] : 0;
|
||||
|
||||
$tpl = get_markup_template('invite.tpl');
|
||||
|
||||
$inv_rabots = array(
|
||||
@@ -420,11 +403,11 @@ class Invite extends Controller {
|
||||
'field' => array(
|
||||
'name' => 'expire',
|
||||
'title' => t('duration up from now'),
|
||||
'value' => ($invexpire_n ? $invexpire_n : 2),
|
||||
'value' => 2,
|
||||
'min' => '1',
|
||||
'max' => '99',
|
||||
'size' => '2',
|
||||
'default' => ($invexpire_u ? $invexpire_u : 'd')
|
||||
'default' => 'd',
|
||||
),
|
||||
'rabot' => $inv_rabots
|
||||
)
|
||||
@@ -583,5 +566,18 @@ class Invite extends Controller {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find how many invites the given channel is currently using.
|
||||
*
|
||||
* @param int $channel_id The id of the channel
|
||||
*
|
||||
* @return int Number of invites this channel is currently using.
|
||||
*/
|
||||
private function count_invites_by_user(int $channel): int {
|
||||
$r = q("SELECT count(reg_id) AS n FROM register WHERE reg_vital = 1 AND reg_byc = %d", $channel);
|
||||
|
||||
return $r ? $r[0]['n'] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ class Item extends Controller {
|
||||
// This will change. Figure out who the observer is and whether or not
|
||||
// they have permission to post here. Else ignore the post.
|
||||
|
||||
if ((!local_channel()) && (!remote_channel()) && (!x($_REQUEST, 'anonname')))
|
||||
if ((!local_channel()) && (!remote_channel()) && (empty($_POST['anonname'])))
|
||||
return;
|
||||
|
||||
$uid = local_channel();
|
||||
@@ -107,12 +107,13 @@ class Item extends Controller {
|
||||
* Is this a reply to something?
|
||||
*/
|
||||
|
||||
$parent = ((x($_REQUEST, 'parent')) ? intval($_REQUEST['parent']) : 0);
|
||||
$parent_mid = ((x($_REQUEST, 'parent_mid')) ? trim($_REQUEST['parent_mid']) : '');
|
||||
$mode = ((isset($_REQUEST['conv_mode']) && $_REQUEST['conv_mode'] === 'channel') ? 'channel' : 'network');
|
||||
$parent = ((!empty($_POST['parent'])) ? intval($_POST['parent']) : 0);
|
||||
$thr_parent_id = $parent;
|
||||
$parent_mid = ((!empty($_POST['parent_mid'])) ? trim($_POST['parent_mid']) : '');
|
||||
$mode = ((isset($_POST['conv_mode']) && $_POST['conv_mode'] === 'channel') ? 'channel' : 'network');
|
||||
|
||||
$remote_xchan = ((x($_REQUEST, 'remote_xchan')) ? trim($_REQUEST['remote_xchan']) : false);
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
$remote_xchan = ((!empty($_POST['remote_xchan'])) ? trim($_POST['remote_xchan']) : false);
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($remote_xchan)
|
||||
);
|
||||
if ($r)
|
||||
@@ -120,7 +121,7 @@ class Item extends Controller {
|
||||
else
|
||||
$remote_xchan = $remote_observer = false;
|
||||
|
||||
$profile_uid = ((x($_REQUEST, 'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0);
|
||||
$profile_uid = ((!empty($_POST['profile_uid'])) ? intval($_POST['profile_uid']) : 0);
|
||||
require_once('include/channel.php');
|
||||
|
||||
$sys = get_sys_channel();
|
||||
@@ -130,25 +131,25 @@ class Item extends Controller {
|
||||
$observer = $sys;
|
||||
}
|
||||
|
||||
if (x($_REQUEST, 'dropitems')) {
|
||||
if (!empty($_POST['dropitems'])) {
|
||||
require_once('include/items.php');
|
||||
$arr_drop = explode(',', $_REQUEST['dropitems']);
|
||||
$arr_drop = explode(',', $_POST['dropitems']);
|
||||
drop_items($arr_drop);
|
||||
$json = ['success' => 1];
|
||||
echo json_encode($json);
|
||||
killme();
|
||||
}
|
||||
|
||||
call_hooks('post_local_start', $_REQUEST);
|
||||
call_hooks('post_local_start', $_POST);
|
||||
|
||||
// logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
|
||||
// logger('postvars ' . print_r($_POST,true), LOGGER_DATA);
|
||||
|
||||
$api_source = ((x($_REQUEST, 'api_source') && $_REQUEST['api_source']) ? true : false);
|
||||
$api_source = ((!empty($_POST['api_source'])) ? true : false);
|
||||
|
||||
$consensus = $_REQUEST['consensus'] ?? 0;
|
||||
$nocomment = $_REQUEST['nocomment'] ?? 0;
|
||||
$consensus = $_POST['consensus'] ?? 0;
|
||||
$nocomment = $_POST['nocomment'] ?? 0;
|
||||
|
||||
$is_poll = ((isset($_REQUEST['poll_answers'][0]) && $_REQUEST['poll_answers'][0]) && (isset($_REQUEST['poll_answers'][1]) && $_REQUEST['poll_answers'][1]));
|
||||
$is_poll = ((isset($_POST['poll_answers'][0]) && $_POST['poll_answers'][0]) && (isset($_POST['poll_answers'][1]) && $_POST['poll_answers'][1]));
|
||||
|
||||
// 'origin' (if non-zero) indicates that this network is where the message originated,
|
||||
// for the purpose of relaying comments to other conversation members.
|
||||
@@ -159,43 +160,43 @@ class Item extends Controller {
|
||||
|
||||
// If you are unsure, it is prudent (and important) to leave it unset.
|
||||
|
||||
$origin = (($api_source && array_key_exists('origin', $_REQUEST)) ? intval($_REQUEST['origin']) : 1);
|
||||
$origin = (($api_source && array_key_exists('origin', $_POST)) ? intval($_REQU_POSTEST['origin']) : 1);
|
||||
|
||||
// To represent message-ids on other networks - this will create an iconfig record
|
||||
|
||||
$namespace = (($api_source && array_key_exists('namespace', $_REQUEST)) ? strip_tags($_REQUEST['namespace']) : '');
|
||||
$remote_id = (($api_source && array_key_exists('remote_id', $_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : '');
|
||||
$namespace = (($api_source && array_key_exists('namespace', $_POST)) ? strip_tags($_POST['namespace']) : '');
|
||||
$remote_id = (($api_source && array_key_exists('remote_id', $_POST)) ? strip_tags($_POST['remote_id']) : '');
|
||||
|
||||
$owner_hash = null;
|
||||
|
||||
$message_id = ((x($_REQUEST, 'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : null);
|
||||
$created = ((x($_REQUEST, 'created')) ? datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['created']) : datetime_convert());
|
||||
$post_id = ((x($_REQUEST, 'post_id')) ? intval($_REQUEST['post_id']) : 0);
|
||||
$app = ((x($_REQUEST, 'source')) ? strip_tags($_REQUEST['source']) : '');
|
||||
$return_path = ((x($_REQUEST, 'return')) ? $_REQUEST['return'] : '');
|
||||
$preview = ((x($_REQUEST, 'preview')) ? intval($_REQUEST['preview']) : 0);
|
||||
$categories = ((x($_REQUEST, 'category')) ? escape_tags($_REQUEST['category']) : '');
|
||||
$webpage = ((x($_REQUEST, 'webpage')) ? intval($_REQUEST['webpage']) : 0);
|
||||
$item_obscured = ((x($_REQUEST, 'obscured')) ? intval($_REQUEST['obscured']) : 0);
|
||||
$item_delayed = ((x($_REQUEST, 'delayed')) ? intval($_REQUEST['delayed']) : 0);
|
||||
$pagetitle = ((x($_REQUEST, 'pagetitle')) ? escape_tags($_REQUEST['pagetitle']) : '');
|
||||
$layout_mid = ((x($_REQUEST, 'layout_mid')) ? escape_tags($_REQUEST['layout_mid']) : '');
|
||||
$plink = ((x($_REQUEST, 'permalink')) ? escape_tags($_REQUEST['permalink']) : '');
|
||||
$obj_type = ((x($_REQUEST, 'obj_type')) ? escape_tags($_REQUEST['obj_type']) : 'Note');
|
||||
$message_id = ((!empty($_POST['message_id']) && $api_source) ? strip_tags($_POST['message_id']) : null);
|
||||
$created = ((!empty($_POST['created'])) ? datetime_convert(date_default_timezone_get(), 'UTC', $_POST['created']) : datetime_convert());
|
||||
$post_id = ((!empty($_POST['post_id'])) ? intval($_POST['post_id']) : 0);
|
||||
$app = ((!empty($_POST['source'])) ? strip_tags($_POST['source']) : '');
|
||||
$return_path = ((!empty($_POST['return'])) ? $_POST['return'] : '');
|
||||
$preview = ((!empty($_POST['preview'])) ? intval($_POST['preview']) : 0);
|
||||
$categories = ((!empty($_POST['category'])) ? escape_tags($_POST['category']) : '');
|
||||
$item_type = ((!empty($_POST['webpage'])) ? intval($_POST['webpage']) : ITEM_TYPE_POST);
|
||||
$item_obscured = ((!empty($_POST['obscured'])) ? intval($_POST['obscured']) : 0);
|
||||
$item_delayed = ((!empty($_POST['delayed'])) ? intval($_POST['delayed']) : 0);
|
||||
$pagetitle = ((!empty($_POST['pagetitle'])) ? escape_tags($_POST['pagetitle']) : '');
|
||||
$layout_mid = ((!empty($_POST['layout_mid'])) ? escape_tags($_POST['layout_mid']) : '');
|
||||
$plink = ((!empty($_POST['permalink'])) ? escape_tags($_POST['permalink']) : null);
|
||||
$obj_type = ((!empty($_POST['obj_type'])) ? escape_tags($_POST['obj_type']) : 'Note');
|
||||
|
||||
// allow API to bulk load a bunch of imported items with sending out a bunch of posts.
|
||||
$nopush = ((x($_REQUEST, 'nopush')) ? intval($_REQUEST['nopush']) : 0);
|
||||
$nopush = ((!empty($_POST['nopush'])) ? intval($_POST['nopush']) : 0);
|
||||
|
||||
/*
|
||||
* Check service class limits
|
||||
*/
|
||||
if ($uid && !(x($_REQUEST, 'parent')) && !(x($_REQUEST, 'post_id'))) {
|
||||
$ret = $this->item_check_service_class($uid, (($_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false));
|
||||
if ($uid && empty($_POST['parent']) && empty($_POST['post_id'])) {
|
||||
$ret = $this->item_check_service_class($uid, (($_POST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false));
|
||||
if (!$ret['success']) {
|
||||
notice(t($ret['message']) . EOL);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'service class exception']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -216,8 +217,8 @@ class Item extends Controller {
|
||||
|
||||
if ($parent || $parent_mid) {
|
||||
|
||||
if (!x($_REQUEST, 'type'))
|
||||
$_REQUEST['type'] = 'net-comment';
|
||||
if (empty($_POST['type']))
|
||||
$_POST['type'] = 'net-comment';
|
||||
|
||||
if ($parent) {
|
||||
$r = q("SELECT * FROM item WHERE id = %d LIMIT 1",
|
||||
@@ -253,7 +254,7 @@ class Item extends Controller {
|
||||
notice(t('Unable to locate original post.') . EOL);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'invalid post id']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -276,7 +277,7 @@ class Item extends Controller {
|
||||
if (!$observer) {
|
||||
$observer = App::get_observer();
|
||||
if (!$observer) {
|
||||
$observer = anon_identity_init($_REQUEST);
|
||||
$observer = anon_identity_init($_POST);
|
||||
if ($observer) {
|
||||
$moderated = true;
|
||||
$remote_xchan = $remote_observer = $observer;
|
||||
@@ -288,7 +289,7 @@ class Item extends Controller {
|
||||
notice(t('Permission denied.') . EOL);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'permission denied']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -307,17 +308,17 @@ class Item extends Controller {
|
||||
notice(t('Permission denied.') . EOL);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'permission denied']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], ($webpage) ? 'write_pages' : 'post_wall')) {
|
||||
if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], (intval($item_type) === ITEM_TYPE_POST) ? 'post_wall' : 'write_pages')) {
|
||||
notice(t('Permission denied.') . EOL);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'permission denied']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -373,7 +374,7 @@ class Item extends Controller {
|
||||
logger("mod_item: no channel.");
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'no channel']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -383,6 +384,7 @@ class Item extends Controller {
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($channel['channel_hash'])
|
||||
);
|
||||
|
||||
if ($r && count($r)) {
|
||||
$owner_xchan = $r[0];
|
||||
}
|
||||
@@ -390,7 +392,7 @@ class Item extends Controller {
|
||||
logger("mod_item: no owner.");
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'no owner']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -424,17 +426,21 @@ class Item extends Controller {
|
||||
$view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'view_stream');
|
||||
$comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'post_comments');
|
||||
|
||||
$public_policy = ((x($_REQUEST, 'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy, true));
|
||||
if ($webpage)
|
||||
$public_policy = '';
|
||||
if ($public_policy)
|
||||
$public_policy = '';
|
||||
|
||||
if (intval($item_type) === ITEM_TYPE_POST) {
|
||||
$public_policy = ((!empty($_POST['public_policy'])) ? escape_tags($_POST['public_policy']) : map_scope($view_policy, true));
|
||||
}
|
||||
|
||||
if ($public_policy) {
|
||||
$private = 1;
|
||||
}
|
||||
|
||||
if ($orig_post) {
|
||||
$private = 0;
|
||||
// webpages are allowed to change ACLs after the fact. Normal conversation items aren't.
|
||||
if ($webpage) {
|
||||
$acl->set_from_array($_REQUEST);
|
||||
// Normal conversation items are not allowed to change ACL.
|
||||
if (intval($item_type) !== ITEM_TYPE_POST) {
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
else {
|
||||
$acl->set($orig_post);
|
||||
@@ -450,9 +456,9 @@ class Item extends Controller {
|
||||
$coord = $orig_post['coord'];
|
||||
$verb = $orig_post['verb'];
|
||||
$app = $orig_post['app'];
|
||||
$title = escape_tags(trim($_REQUEST['title']));
|
||||
$summary = escape_tags(trim($_REQUEST['summary']));
|
||||
$body = trim($_REQUEST['body']);
|
||||
$title = escape_tags(trim($_POST['title']));
|
||||
$summary = escape_tags(trim($_POST['summary']));
|
||||
$body = trim($_POST['body']);
|
||||
$item_flags = $orig_post['item_flags'];
|
||||
$item_origin = $orig_post['item_origin'];
|
||||
$item_unseen = $orig_post['item_unseen'];
|
||||
@@ -486,14 +492,15 @@ class Item extends Controller {
|
||||
$thr_parent = $orig_post['thr_parent'];
|
||||
$parent_mid = $orig_post['parent_mid'];
|
||||
$plink = $orig_post['plink'];
|
||||
$owner_hash = $orig_post['owner_xchan'];
|
||||
}
|
||||
else {
|
||||
if (!$walltowall) {
|
||||
if ((array_key_exists('contact_allow', $_REQUEST))
|
||||
|| (array_key_exists('group_allow', $_REQUEST))
|
||||
|| (array_key_exists('contact_deny', $_REQUEST))
|
||||
|| (array_key_exists('group_deny', $_REQUEST))) {
|
||||
$acl->set_from_array($_REQUEST);
|
||||
if ((array_key_exists('contact_allow', $_POST))
|
||||
|| (array_key_exists('group_allow', $_POST))
|
||||
|| (array_key_exists('contact_deny', $_POST))
|
||||
|| (array_key_exists('group_deny', $_POST))) {
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
elseif (!$api_source) {
|
||||
|
||||
@@ -508,16 +515,16 @@ class Item extends Controller {
|
||||
}
|
||||
|
||||
|
||||
$location = ((isset($_REQUEST['location'])) ? notags(trim($_REQUEST['location'])) : '');
|
||||
$coord = ((isset($_REQUEST['coord'])) ? notags(trim($_REQUEST['coord'])) : '');
|
||||
$verb = ((isset($_REQUEST['verb'])) ? notags(trim($_REQUEST['verb'])) : '');
|
||||
$title = ((isset($_REQUEST['title'])) ? escape_tags(trim($_REQUEST['title'])) : '');
|
||||
$summary = ((isset($_REQUEST['summary'])) ? escape_tags(trim($_REQUEST['summary'])) : '');
|
||||
$body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : '');
|
||||
$body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : '');
|
||||
$location = ((isset($_POST['location'])) ? notags(trim($_POST['location'])) : '');
|
||||
$coord = ((isset($_POST['coord'])) ? notags(trim($_POST['coord'])) : '');
|
||||
$verb = ((isset($_POST['verb'])) ? notags(trim($_POST['verb'])) : '');
|
||||
$title = ((isset($_POST['title'])) ? escape_tags(trim($_POST['title'])) : '');
|
||||
$summary = ((isset($_POST['summary'])) ? escape_tags(trim($_POST['summary'])) : '');
|
||||
$body = ((isset($_POST['body'])) ? trim($_POST['body']) : '');
|
||||
$body .= ((isset($_POST['attachment'])) ? trim($_POST['attachment']) : '');
|
||||
$postopts = '';
|
||||
|
||||
$allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
|
||||
$allow_empty = ((array_key_exists('allow_empty', $_POST)) ? intval($_POST['allow_empty']) : 0);
|
||||
|
||||
$private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy)));
|
||||
|
||||
@@ -528,7 +535,7 @@ class Item extends Controller {
|
||||
$private = intval($parent_item['item_private']);
|
||||
$public_policy = $parent_item['public_policy'];
|
||||
$owner_hash = $parent_item['owner_xchan'];
|
||||
$webpage = $parent_item['item_type'];
|
||||
$item_type = $parent_item['item_type'];
|
||||
}
|
||||
|
||||
|
||||
@@ -539,7 +546,7 @@ class Item extends Controller {
|
||||
info(t('Empty post discarded.') . EOL);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'no content']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -547,15 +554,15 @@ class Item extends Controller {
|
||||
|
||||
|
||||
if (feature_enabled($profile_uid, 'content_expire')) {
|
||||
if (x($_REQUEST, 'expire')) {
|
||||
$expires = datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['expire']);
|
||||
if (!empty($_POST['expire'])) {
|
||||
$expires = datetime_convert(date_default_timezone_get(), 'UTC', $_POST['expire']);
|
||||
if ($expires <= datetime_convert())
|
||||
$expires = NULL_DATE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$mimetype = ((isset($_REQUEST['mimetype'])) ? notags(trim($_REQUEST['mimetype'])) : '');
|
||||
$mimetype = ((isset($_POST['mimetype'])) ? notags(trim($_POST['mimetype'])) : '');
|
||||
|
||||
if (!$mimetype)
|
||||
$mimetype = 'text/bbcode';
|
||||
@@ -589,7 +596,7 @@ class Item extends Controller {
|
||||
|
||||
$is_group = get_pconfig($profile_uid, 'system', 'group_actor');
|
||||
|
||||
if ($is_group && $walltowall && !$walltowall_comment && !$webpage) {
|
||||
if ($is_group && $walltowall && !$walltowall_comment && (intval($item_type) === ITEM_TYPE_POST)) {
|
||||
$groupww = true;
|
||||
$str_contact_allow = $owner_xchan['xchan_hash'];
|
||||
$str_group_allow = '';
|
||||
@@ -788,7 +795,7 @@ class Item extends Controller {
|
||||
}
|
||||
|
||||
$item_unseen = ((local_channel() != $profile_uid) ? 1 : 0);
|
||||
$item_wall = ((isset($_REQUEST['type']) && ($_REQUEST['type'] === 'wall' || $_REQUEST['type'] === 'wall-comment')) ? 1 : 0);
|
||||
$item_wall = ((isset($_POST['type']) && ($_POST['type'] === 'wall' || $_POST['type'] === 'wall-comment')) ? 1 : 0);
|
||||
$item_origin = (($origin) ? 1 : 0);
|
||||
$item_consensus = (($consensus) ? 1 : 0);
|
||||
$item_nocomment = (($nocomment) ? 1 : 0);
|
||||
@@ -796,15 +803,13 @@ class Item extends Controller {
|
||||
|
||||
// determine if this is a wall post
|
||||
|
||||
if (in_array($item_type, [ITEM_TYPE_POST, ITEM_TYPE_CARD, ITEM_TYPE_ARTICLE])) {
|
||||
$item_wall = 1;
|
||||
}
|
||||
|
||||
if ($parent) {
|
||||
$item_wall = $parent_item['item_wall'];
|
||||
}
|
||||
else {
|
||||
if (!$webpage) {
|
||||
$item_wall = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($moderated) {
|
||||
$item_blocked = ITEM_MODERATED;
|
||||
@@ -821,36 +826,34 @@ class Item extends Controller {
|
||||
$mid = $mid ?? z_root() . '/item/' . $uuid;
|
||||
|
||||
|
||||
// Set the conversation target.
|
||||
if (empty($owner_hash)) {
|
||||
$owner_hash = $owner_xchan['xchan_hash'];
|
||||
}
|
||||
|
||||
if ($owner_hash === $channel['channel_hash']) {
|
||||
$attributedTo = z_root() . '/channel/' . $channel['channel_address'];
|
||||
|
||||
$conversation = isset($parent_item) ? $parent_item['mid'] : $mid;
|
||||
$datarray['target'] = [
|
||||
'id' => str_replace('/item/', '/conversation/', $conversation),
|
||||
'type' => 'Collection',
|
||||
'attributedTo' => $attributedTo,
|
||||
];
|
||||
$datarray['tgt_type'] = 'Collection';
|
||||
}
|
||||
elseif (!empty($parent_item['target'])) {
|
||||
$datarray['target'] = $parent_item['target'];
|
||||
$datarray['tgt_type'] = $parent_item['tgt_type'];
|
||||
}
|
||||
if (empty($owner_hash)) {
|
||||
$owner_hash = $owner_xchan['xchan_hash'];
|
||||
}
|
||||
|
||||
// Set the conversation target.
|
||||
if ($owner_hash === $channel['channel_hash']) {
|
||||
$attributedTo = z_root() . '/channel/' . $channel['channel_address'];
|
||||
|
||||
$conversation = isset($parent_item) ? $parent_item['mid'] : $mid;
|
||||
$datarray['target'] = [
|
||||
'id' => str_replace('/item/', '/conversation/', $conversation),
|
||||
'type' => 'Collection',
|
||||
'attributedTo' => $attributedTo,
|
||||
];
|
||||
$datarray['tgt_type'] = 'Collection';
|
||||
}
|
||||
elseif (!empty($parent_item['target'])) {
|
||||
$datarray['target'] = $parent_item['target'];
|
||||
$datarray['tgt_type'] = $parent_item['tgt_type'];
|
||||
}
|
||||
|
||||
if ($is_poll) {
|
||||
$poll = [
|
||||
'question' => $body,
|
||||
'answers' => $_REQUEST['poll_answers'],
|
||||
'multiple_answers' => $_REQUEST['poll_multiple_answers'],
|
||||
'expire_value' => $_REQUEST['poll_expire_value'],
|
||||
'expire_unit' => $_REQUEST['poll_expire_unit']
|
||||
'answers' => $_POST['poll_answers'],
|
||||
'multiple_answers' => $_POST['poll_multiple_answers'],
|
||||
'expire_value' => $_POST['poll_expire_value'],
|
||||
'expire_unit' => $_POST['poll_expire_unit']
|
||||
];
|
||||
$obj = $this->extract_poll_data($poll, ['item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny]);
|
||||
}
|
||||
@@ -885,19 +888,13 @@ class Item extends Controller {
|
||||
if ($parent_item)
|
||||
$parent_mid = $parent_item['mid'];
|
||||
|
||||
|
||||
// Fallback so that we always have a thr_parent
|
||||
|
||||
if (!$thr_parent)
|
||||
$thr_parent = $mid;
|
||||
|
||||
|
||||
$item_thread_top = ((!$parent) ? 1 : 0);
|
||||
|
||||
if ((!$plink) && ($item_thread_top)) {
|
||||
$plink = $mid;
|
||||
}
|
||||
|
||||
if (isset($datarray['obj']) && $datarray['obj']) {
|
||||
$datarray['obj']['id'] = $mid;
|
||||
}
|
||||
@@ -935,7 +932,7 @@ class Item extends Controller {
|
||||
$datarray['item_unseen'] = intval($item_unseen);
|
||||
$datarray['item_wall'] = intval($item_wall);
|
||||
$datarray['item_origin'] = intval($item_origin);
|
||||
$datarray['item_type'] = $webpage;
|
||||
$datarray['item_type'] = $item_type;
|
||||
$datarray['item_private'] = intval($private);
|
||||
$datarray['item_thread_top'] = intval($item_thread_top);
|
||||
$datarray['item_starred'] = intval($item_starred);
|
||||
@@ -960,7 +957,7 @@ class Item extends Controller {
|
||||
$datarray['public_policy'] = $public_policy;
|
||||
$datarray['comment_policy'] = map_scope($comment_policy);
|
||||
$datarray['term'] = array_unique($post_tags, SORT_REGULAR);
|
||||
$datarray['plink'] = $plink;
|
||||
$datarray['plink'] = $plink ?? $mid;
|
||||
$datarray['route'] = $route;
|
||||
|
||||
// A specific ACL over-rides public_policy completely
|
||||
@@ -1014,14 +1011,14 @@ class Item extends Controller {
|
||||
|
||||
call_hooks('post_local', $datarray);
|
||||
|
||||
if (x($datarray, 'cancel')) {
|
||||
if (!empty($datarray['cancel'])) {
|
||||
logger('mod_item: post cancelled by plugin or duplicate suppressed.');
|
||||
if ($return_path)
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'operation cancelled']);
|
||||
$json = ['cancel' => 1];
|
||||
$json['reload'] = z_root() . '/' . $_REQUEST['jsreload'];
|
||||
$json['reload'] = z_root() . '/' . $_POST['jsreload'];
|
||||
echo json_encode($json);
|
||||
killme();
|
||||
}
|
||||
@@ -1030,8 +1027,8 @@ class Item extends Controller {
|
||||
if (mb_strlen($datarray['title']) > 191)
|
||||
$datarray['title'] = mb_substr($datarray['title'], 0, 191);
|
||||
|
||||
if ($webpage) {
|
||||
IConfig::Set($datarray, 'system', webpage_to_namespace($webpage),
|
||||
if (intval($item_type) !== ITEM_TYPE_POST) {
|
||||
IConfig::Set($datarray, 'system', item_type_to_namespace($item_type),
|
||||
(($pagetitle) ? $pagetitle : basename($datarray['mid'])), true);
|
||||
}
|
||||
elseif ($namespace) {
|
||||
@@ -1071,7 +1068,7 @@ class Item extends Controller {
|
||||
if ($api_source)
|
||||
return ($x);
|
||||
|
||||
if ((x($_REQUEST, 'return')) && strlen($return_path)) {
|
||||
if ((!empty($_POST['return'])) && strlen($return_path)) {
|
||||
logger('return: ' . $return_path);
|
||||
|
||||
if ($return_path === 'hq') {
|
||||
@@ -1224,11 +1221,12 @@ class Item extends Controller {
|
||||
$json = [
|
||||
'success' => 1,
|
||||
'id' => $post_id,
|
||||
'thr_parent_id' => $thr_parent_id,
|
||||
'html' => conversation($item, $mode, true, 'r_preview'),
|
||||
];
|
||||
|
||||
if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload']))
|
||||
$json['reload'] = z_root() . '/' . $_REQUEST['jsreload'];
|
||||
if (!empty($_POST['jsreload']))
|
||||
$json['reload'] = z_root() . '/' . $_POST['jsreload'];
|
||||
|
||||
logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
|
||||
|
||||
@@ -1503,7 +1501,7 @@ class Item extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -1619,7 +1617,7 @@ class Item extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
|
||||
@@ -65,8 +65,22 @@ class Lang extends Controller {
|
||||
}
|
||||
|
||||
nav_set_selected('Language');
|
||||
return lang_selector();
|
||||
return $this->lang_selector();
|
||||
|
||||
}
|
||||
|
||||
private function lang_selector(): string
|
||||
{
|
||||
$lang_options = language_list();
|
||||
array_unshift($lang_options, t('default'));
|
||||
|
||||
$tpl = get_markup_template('lang_selector.tpl');
|
||||
|
||||
return replace_macros($tpl, [
|
||||
'$title' => t('Select an alternate language'),
|
||||
'$langs' => array($lang_options, App::$language),
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ class Like extends Controller {
|
||||
'like' => 'Like',
|
||||
'dislike' => 'Dislike',
|
||||
'announce' => ACTIVITY_SHARE,
|
||||
'attendyes' => 'Accept',
|
||||
'attendno' => 'Reject',
|
||||
'attendmaybe' => 'TentativeAccept'
|
||||
'accept' => 'Accept',
|
||||
'reject' => 'Reject',
|
||||
'tentativeaccept' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
// unlike (etc.) reactions are an undo of positive reactions, rather than a negative action.
|
||||
@@ -52,43 +52,31 @@ class Like extends Controller {
|
||||
profile_load($parts[0]);
|
||||
}
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
if ($page_mode === 'list') {
|
||||
$item_normal = item_normal();
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id FROM item
|
||||
WHERE uid = %d $item_normal
|
||||
AND parent = %d",
|
||||
intval($arr['item']['uid']),
|
||||
intval($arr['item']['parent'])
|
||||
);
|
||||
|
||||
xchan_query($items, true);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$items = conv_sort($items, 'commented');
|
||||
}
|
||||
else {
|
||||
$activities = q("SELECT item.*, item.id AS item_id FROM item
|
||||
WHERE uid = %d $item_normal
|
||||
AND thr_parent = '%s'
|
||||
AND verb IN ('%s', '%s', '%s', '%s', '%s', '%s', 'Accept', 'Reject', 'TentativeAccept')",
|
||||
intval($arr['item']['uid']),
|
||||
dbesc($arr['item']['mid']),
|
||||
dbesc('Like'),
|
||||
dbesc('Dislike'),
|
||||
dbesc(ACTIVITY_SHARE),
|
||||
dbesc(ACTIVITY_ATTEND),
|
||||
dbesc(ACTIVITY_ATTENDNO),
|
||||
dbesc(ACTIVITY_ATTENDMAYBE)
|
||||
);
|
||||
xchan_query($activities, true);
|
||||
$items = array_merge([$arr['item']], $activities);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$item = item_by_item_id($arr['item']['id'], $arr['item']['parent']);
|
||||
xchan_query($item, true);
|
||||
$item = fetch_post_tags($item, true);
|
||||
}
|
||||
|
||||
$ret = [
|
||||
'success' => 1,
|
||||
'orig_id' => $arr['orig_item_id'], //this is required for pubstream items where $item_id != $item['id']
|
||||
'id' => $arr['item']['id'],
|
||||
'html' => conversation($items, $conv_mode, true, $page_mode),
|
||||
'html' => conversation($item, $conv_mode, true, $page_mode),
|
||||
];
|
||||
|
||||
// mod photos
|
||||
@@ -486,11 +474,11 @@ class Like extends Controller {
|
||||
$bodyverb = t('%1$s likes %2$s\'s %3$s');
|
||||
if ($verb === 'dislike')
|
||||
$bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
|
||||
if ($verb === 'attendyes')
|
||||
if ($verb === 'accept')
|
||||
$bodyverb = t('%1$s is attending %2$s\'s %3$s');
|
||||
if ($verb === 'attendno')
|
||||
if ($verb === 'reject')
|
||||
$bodyverb = t('%1$s is not attending %2$s\'s %3$s');
|
||||
if ($verb === 'attendmaybe')
|
||||
if ($verb === 'tentativeaccept')
|
||||
$bodyverb = t('%1$s may attend %2$s\'s %3$s');
|
||||
|
||||
if (!isset($bodyverb))
|
||||
@@ -573,7 +561,7 @@ class Like extends Controller {
|
||||
|
||||
call_hooks('post_local_end', $arr);
|
||||
|
||||
if ($is_rsvp && in_array($verb, ['attendyes', 'attendmaybe'])) {
|
||||
if ($is_rsvp && in_array($verb, ['accept', 'tentativeaccept'])) {
|
||||
event_addtocal($item_id, local_channel());
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,28 @@ namespace Zotlabs\Module;
|
||||
class Login extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
if(local_channel())
|
||||
goaway(z_root());
|
||||
if(remote_channel() && $_SESSION['atoken'])
|
||||
if (local_channel()) {
|
||||
goaway(z_root());
|
||||
}
|
||||
|
||||
return login(true);
|
||||
if (remote_channel() && $_SESSION['atoken']) {
|
||||
goaway(z_root());
|
||||
}
|
||||
|
||||
if (!empty($_GET['retry'])) {
|
||||
notice( t('Login failed.') . EOL );
|
||||
}
|
||||
|
||||
$o = '<div class="generic-content-wrapper">';
|
||||
$o .= '<div class="section-title-wrapper">';
|
||||
$o .= '<h2 class="">' . t('Login') . '</h2>';
|
||||
$o .= '</div>';
|
||||
$o .= '<div class="section-content-wrapper">';
|
||||
$o .= login(true);
|
||||
$o .= '</div>';
|
||||
$o .= '</div>';
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,11 +41,7 @@ class Magic extends Controller {
|
||||
http_status_exit(400, 'Bad Request');
|
||||
}
|
||||
|
||||
$basepath = unparse_url(array_filter(
|
||||
$parsed,
|
||||
fn (string $key) => in_array($key, ['scheme', 'host', 'port']),
|
||||
ARRAY_FILTER_USE_KEY
|
||||
));
|
||||
$basepath = unparse_url($parsed, ['scheme', 'host', 'port']);
|
||||
|
||||
$owapath = SConfig::get($basepath, 'system', 'openwebauth', $basepath . '/owa');
|
||||
|
||||
@@ -134,11 +130,22 @@ class Magic extends Controller {
|
||||
$args = (($x) ? '&owt=' . $token : '?owt=' . $token) . (($delegate) ? '&delegate=1' : '');
|
||||
goaway($dest . $args);
|
||||
}
|
||||
else {
|
||||
$o = '<h1>OWA ERROR</h1>';
|
||||
if (!empty($j['message'])) {
|
||||
$o .= '<h2>' . $j['message'] . '</h2>';
|
||||
}
|
||||
$o .= '<a href=' . $dest . '>' . $dest . '</a>';
|
||||
|
||||
echo $o;
|
||||
killme();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
killme();
|
||||
goaway($dest);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class Moderate extends \Zotlabs\Web\Controller {
|
||||
|
||||
$item['item_blocked'] = 0;
|
||||
item_update_parent_commented($item);
|
||||
notice( t('Item approved') . EOL);
|
||||
info(t('Item approved') . EOL);
|
||||
}
|
||||
elseif($action === 'drop') {
|
||||
// TODO: not implemented
|
||||
@@ -75,7 +75,7 @@ class Moderate extends \Zotlabs\Web\Controller {
|
||||
// Activity::send_rejection_activity(App::get_channel(), $item['author_xchan'], $item);
|
||||
|
||||
drop_item($post_id);
|
||||
notice( t('Item deleted') . EOL);
|
||||
info(t('Item deleted') . EOL);
|
||||
}
|
||||
|
||||
// refetch the item after changes have been made
|
||||
|
||||
@@ -70,17 +70,19 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
$dm = ((x($_REQUEST,'dm')) ? $_REQUEST['dm'] : 0);
|
||||
|
||||
|
||||
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
|
||||
$order = get_pconfig(local_channel(), 'mod_network', 'order', 'created');
|
||||
switch($order) {
|
||||
case 0:
|
||||
$order = 'comment';
|
||||
case 'commented':
|
||||
$ordering = 'commented';
|
||||
break;
|
||||
case 1:
|
||||
$order = 'post';
|
||||
case 'created':
|
||||
$ordering = 'created';
|
||||
break;
|
||||
case 2:
|
||||
case 'unthreaded':
|
||||
$nouveau = true;
|
||||
break;
|
||||
default:
|
||||
$ordering = 'created';
|
||||
}
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
@@ -92,7 +94,7 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($datequery)
|
||||
$order = 'post';
|
||||
$order = 'created';
|
||||
|
||||
|
||||
// filter by collection (e.g. group)
|
||||
@@ -201,7 +203,7 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
'default_location' => $channel['channel_location'],
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($private_editing || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
|
||||
'acl' => populate_acl((($private_editing) ? $def_acl : $channel_acl), true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
|
||||
'acl' => populate_acl((($private_editing) ? $def_acl : $channel_acl), true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'member/permissions'),
|
||||
'permissions' => (($private_editing) ? $def_acl : $channel_acl),
|
||||
'bang' => (($private_editing) ? $bang : ''),
|
||||
'visitor' => true,
|
||||
@@ -274,36 +276,18 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
elseif($pf && $unseen && $nouveau) {
|
||||
|
||||
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify');
|
||||
if(! ($vnotify & VNOTIFY_LIKE))
|
||||
$likes_sql = '';
|
||||
if (!($vnotify & VNOTIFY_LIKE)) {
|
||||
$likes_sql = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
|
||||
// This is for nouveau view public forum cid queries (if a forum notification is clicked)
|
||||
//$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
|
||||
//intval(local_channel()),
|
||||
//intval(TERM_FORUM),
|
||||
//dbesc($cid_r[0]['xchan_name'])
|
||||
//);
|
||||
$sql_extra = " AND item.parent IN (SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal) AND item_unseen = 1 AND verb != 'Announce' $likes_sql ";
|
||||
|
||||
//$p_str = ids_to_querystr($p, 'parent');
|
||||
|
||||
$p_sql = '';
|
||||
//if($p_str)
|
||||
//$p_sql = " OR item.parent IN ( $p_str ) ";
|
||||
|
||||
$sql_extra = " AND ( owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' OR owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' $p_sql ) AND item_unseen = 1 $likes_sql ";
|
||||
}
|
||||
else {
|
||||
// This is for threaded view cid queries (e.g. if a forum is selected from the forum filter)
|
||||
$ttype = (($pf) ? TERM_FORUM : TERM_MENTION);
|
||||
|
||||
$p1 = dbq("SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal ");
|
||||
$p2 = dbq("SELECT oid AS parent FROM term WHERE uid = " . intval(local_channel()) . " AND ttype = $ttype AND term = '" . dbesc($cid_r[0]['xchan_name']) . "'");
|
||||
|
||||
$p_str = ids_to_querystr(array_merge($p1, $p2), 'parent');
|
||||
if(! $p_str)
|
||||
killme();
|
||||
|
||||
$sql_extra = " AND item.parent IN ( $p_str ) ";
|
||||
$sql_extra = " AND item.parent IN (SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal) ";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,10 +377,10 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if ($dm) {
|
||||
$sql_extra .= ' AND item_private = 2 ';
|
||||
$sql_extra .= ' AND item.item_private = 2 ';
|
||||
}
|
||||
else {
|
||||
$sql_extra .= ' AND item_private IN (0, 1) ';
|
||||
$sql_extra .= ' AND item.item_private IN (0, 1) ';
|
||||
}
|
||||
|
||||
|
||||
@@ -445,10 +429,12 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
$abook_uids = ' and abook.abook_channel = ' . local_channel() . ' ';
|
||||
$uids = ' and item.uid = ' . local_channel() . ' ';
|
||||
|
||||
if(feature_enabled(local_channel(), 'network_list_mode'))
|
||||
$page_mode = 'client';
|
||||
|
||||
$blog_mode = feature_enabled(local_channel(), 'network_list_mode');
|
||||
if ($blog_mode) {
|
||||
$page_mode = 'list';
|
||||
else
|
||||
$page_mode = 'client';
|
||||
}
|
||||
|
||||
$parents_str = '';
|
||||
|
||||
@@ -472,11 +458,12 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
|
||||
if($nouveau && $load) {
|
||||
// "New Item View" - show all items unthreaded in reverse created date order
|
||||
$items = dbq("SELECT item.*, item.id AS item_id, created FROM item
|
||||
$items = dbq("SELECT item.*, item.id AS item_id FROM item
|
||||
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
|
||||
$net_query
|
||||
WHERE true $uids $item_normal
|
||||
and (abook.abook_blocked = 0 or abook.abook_flags is null)
|
||||
AND item.verb NOT IN ('Add', 'Remove')
|
||||
$sql_extra $sql_options $sql_nets
|
||||
$net_query2
|
||||
ORDER BY item.created DESC $pager_sql "
|
||||
@@ -492,13 +479,6 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
elseif($update) {
|
||||
|
||||
// Normal conversation view
|
||||
|
||||
if($order === 'post')
|
||||
$ordering = 'created';
|
||||
else
|
||||
$ordering = 'commented';
|
||||
|
||||
if($load) {
|
||||
// Fetch a page full of parent items for this page
|
||||
$r = dbq("SELECT item.parent AS item_id FROM item
|
||||
@@ -527,12 +507,7 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
// Then fetch all the children of the parents that are on this page
|
||||
|
||||
if($r) {
|
||||
$parents_str = ids_to_querystr($r, 'item_id');
|
||||
$items = dbq("SELECT item.*, item.id AS item_id FROM item
|
||||
WHERE true $uids $item_normal
|
||||
AND item.parent IN ( $parents_str )
|
||||
$sql_extra "
|
||||
);
|
||||
$items = items_by_parent_ids($r, blog_mode: $blog_mode);
|
||||
|
||||
xchan_query($items, true);
|
||||
$items = fetch_post_tags($items, true);
|
||||
|
||||
@@ -23,6 +23,7 @@ class Oep extends \Zotlabs\Web\Controller {
|
||||
if(! $url)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$arr = [];
|
||||
$maxwidth = $_REQUEST['maxwidth'] ?? 0;
|
||||
$maxheight = $_REQUEST['maxheight'] ?? 0;
|
||||
$format = $_REQUEST['format'] ?? '';
|
||||
|
||||
@@ -18,96 +18,97 @@ use Zotlabs\Web\Controller;
|
||||
|
||||
class Owa extends Controller {
|
||||
|
||||
function init() {
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
$ret = [ 'success' => false ];
|
||||
|
||||
if (array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) {
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER'];
|
||||
if (!$this->validateAuthorizationHeader()) {
|
||||
$this->error('Missing or invalid authorization header.');
|
||||
}
|
||||
|
||||
if (array_key_exists('HTTP_AUTHORIZATION',$_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') {
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
|
||||
if ($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
$parsed = parse_url($keyId);
|
||||
if (str_starts_with($parsed['scheme'],'http')) {
|
||||
unset($parsed['fragment']);
|
||||
unset($parsed['query']);
|
||||
$keyId = unparse_url($parsed);
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_REMOTE_USER'];
|
||||
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
|
||||
if ($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
$parsed = parse_url($keyId);
|
||||
if (str_starts_with($parsed['scheme'],'http')) {
|
||||
unset($parsed['fragment']);
|
||||
unset($parsed['query']);
|
||||
$keyId = unparse_url($parsed);
|
||||
}
|
||||
else {
|
||||
$keyId = str_replace('acct:', '', $keyId);
|
||||
}
|
||||
if ($keyId) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
|
||||
AND hubloc_deleted = 0 AND xchan_pubkey != ''
|
||||
ORDER BY hubloc_id DESC",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
if (! $r) {
|
||||
$found = discover_by_webbie($keyId);
|
||||
logger('found = ' . print_r($found, true));
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$keyId = str_replace('acct:', '', $keyId);
|
||||
}
|
||||
if ($keyId) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
|
||||
AND hubloc_deleted = 0 AND xchan_pubkey != ''
|
||||
ORDER BY hubloc_id DESC",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
if (! $r) {
|
||||
$found = discover_by_webbie($keyId);
|
||||
logger('found = ' . print_r($found, true));
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $hubloc) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
||||
logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
break;
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $hubloc) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
||||
logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
break;
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
if (!$ret['success']) {
|
||||
|
||||
if (!$ret['success']) {
|
||||
// Possible a reinstall?
|
||||
// In this case we probably already have an old hubloc
|
||||
// but not the new one yet.
|
||||
|
||||
// Possible a reinstall?
|
||||
// In this case we probably already have an old hubloc
|
||||
// but not the new one yet.
|
||||
$found = discover_by_webbie($keyId);
|
||||
|
||||
$found = discover_by_webbie($keyId);
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
|
||||
dbesc(str_replace('acct:', '', $keyId)),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
|
||||
dbesc(str_replace('acct:', '', $keyId)),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
|
||||
logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
if ($r) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
|
||||
logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,4 +119,33 @@ class Owa extends Controller {
|
||||
|
||||
json_return_and_die($ret,'application/x-zot+json');
|
||||
}
|
||||
|
||||
private function validateAuthorizationHeader(): bool
|
||||
{
|
||||
if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
$auth = trim($_SERVER['HTTP_AUTHORIZATION']);
|
||||
} else if (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
|
||||
$auth = trim($_SERVER['REDIRECT_REMOTE_USER']);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strncmp($auth, 'Signature', 9) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the request, and return a json error response.
|
||||
*
|
||||
* @Note This function does not return!
|
||||
*
|
||||
* @param string $msg The error message for the response.
|
||||
*/
|
||||
private function error(string $msg): void {
|
||||
$ret = [
|
||||
'success' => false,
|
||||
'message' => $msg
|
||||
];
|
||||
|
||||
json_return_and_die($ret,'application/x-zot+json');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +557,9 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
|
||||
$can_post = false;
|
||||
$visitor = 0;
|
||||
|
||||
$link_item = null;
|
||||
$like = null;
|
||||
$dislike = null;
|
||||
|
||||
$owner_uid = \App::$data['channel']['channel_id'];
|
||||
$owner_aid = \App::$data['channel']['channel_account_id'];
|
||||
@@ -965,7 +967,6 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
$map = null;
|
||||
|
||||
if($linked_items) {
|
||||
|
||||
xchan_query($linked_items);
|
||||
$linked_items = fetch_post_tags($linked_items,true);
|
||||
|
||||
@@ -1103,20 +1104,8 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
$alike = array();
|
||||
$dlike = array();
|
||||
|
||||
$like = '';
|
||||
$dislike = '';
|
||||
|
||||
$conv_responses = array(
|
||||
'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')),
|
||||
'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title'))
|
||||
);
|
||||
|
||||
if($r) {
|
||||
|
||||
foreach($r as $item) {
|
||||
builtin_activity_puller($item, $conv_responses);
|
||||
}
|
||||
|
||||
$like_count = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid']] : '');
|
||||
$like_list = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : '');
|
||||
|
||||
@@ -1217,12 +1206,17 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
$like_e = $like;
|
||||
$dislike_e = $dislike;
|
||||
$paginate = paginate();
|
||||
$responses = [];
|
||||
|
||||
$response_verbs = array('like');
|
||||
if(feature_enabled($owner_uid,'dislike'))
|
||||
$response_verbs[] = 'dislike';
|
||||
if ($link_item) {
|
||||
$response_verbs = ['like'];
|
||||
|
||||
$responses = get_responses($conv_responses,$response_verbs,'',$link_item);
|
||||
if(feature_enabled($owner_uid,'dislike')) {
|
||||
$response_verbs[] = 'dislike';
|
||||
}
|
||||
|
||||
$responses = get_responses($response_verbs, $link_item);
|
||||
}
|
||||
|
||||
$hookdata = [
|
||||
'onclick' => '$.colorbox({href: \'' . $photo['href'] . '\'}); return false;',
|
||||
|
||||
@@ -29,8 +29,9 @@ class Pin extends \Zotlabs\Web\Controller {
|
||||
if(! $observer)
|
||||
http_status_exit(403, 'Forbidden');
|
||||
|
||||
$r = q("SELECT * FROM item WHERE id = %d AND id = parent AND item_private = 0 LIMIT 1",
|
||||
$item_id
|
||||
$r = q("SELECT * FROM item WHERE id = %d AND uid = %d AND id = parent AND item_private = 0 LIMIT 1",
|
||||
intval($item_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
if(! $r) {
|
||||
notice(t('Unable to locate original post.'));
|
||||
|
||||
@@ -84,7 +84,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
|
||||
'default_location' => $channel['channel_location'],
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'member/permissions'),
|
||||
'permissions' => $channel_acl,
|
||||
'bang' => '',
|
||||
'visitor' => true,
|
||||
@@ -183,6 +183,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
|
||||
$sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
|
||||
$sql_extra_order = " ORDER BY item.created DESC ";
|
||||
$thread_top = '';
|
||||
|
||||
}
|
||||
|
||||
$net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : '');
|
||||
@@ -196,7 +197,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
|
||||
|
||||
if($update) {
|
||||
|
||||
$ordering = Config::Get('system', 'pubstream_ordering', 'commented');
|
||||
$ordering = Config::Get('system', 'pubstream_ordering', 'created');
|
||||
|
||||
if($load) {
|
||||
if($mid) {
|
||||
@@ -250,15 +251,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
|
||||
$parents_str = '';
|
||||
|
||||
if($r) {
|
||||
|
||||
$parents_str = ids_to_querystr($r,'item_id');
|
||||
|
||||
$items = dbq("SELECT item.*, item.id AS item_id FROM item
|
||||
WHERE true $uids $item_normal
|
||||
AND item.parent IN ( $parents_str )
|
||||
$sql_extra $sql_extra_order"
|
||||
);
|
||||
|
||||
$items = items_by_parent_ids($r);
|
||||
|
||||
// use effective_uid param of xchan_query to help sort out comment permission
|
||||
// for sys_channel owned items.
|
||||
|
||||
@@ -375,7 +375,7 @@ class Regate extends \Zotlabs\Web\Controller {
|
||||
]);
|
||||
|
||||
$reonar = json_decode( $r['reg_stuff'], true);
|
||||
$reonar['deny'] = $now . ',' . $ip . ' ' . $did2 . ' ' . $msg;
|
||||
$reonar['deny'] = $now . ',' . $ip . ' ' . $did2;
|
||||
$flags = ( $r['reg_flags'] &= ( $r['reg_flags'] ^ ACCOUNT_UNVERIFIED) )
|
||||
| ( $r['reg_flags'] |= REGISTER_DENIED);
|
||||
$rd = q("UPDATE register SET reg_stuff='%s', reg_vital=0, reg_flags=%d WHERE reg_id = %d ",
|
||||
@@ -456,7 +456,7 @@ class Regate extends \Zotlabs\Web\Controller {
|
||||
// $log = ' from § ' . $ip . ' §' . ' (' . dbesc($did2) . ')';
|
||||
zar_log($msg);
|
||||
$o = replace_macros(get_markup_template('plain.tpl'), [
|
||||
'$title' => $title,
|
||||
'$title' => $msg,
|
||||
'$now' => $nowfmt,
|
||||
'$infos' => $msg
|
||||
]);
|
||||
|
||||
89
Zotlabs/Module/Request.php
Normal file
89
Zotlabs/Module/Request.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
class Request extends Controller
|
||||
{
|
||||
|
||||
private function mapVerb(string $verb) : string
|
||||
{
|
||||
$verbs = [
|
||||
'like' => 'Like',
|
||||
'dislike' => 'Dislike',
|
||||
'announce' => 'Announce',
|
||||
'accept' => 'Accept',
|
||||
'reject' => 'Reject',
|
||||
'tentativeaccept' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
if (array_key_exists($verb, $verbs)) {
|
||||
return $verbs[$verb];
|
||||
}
|
||||
|
||||
return EMPTY_STR;
|
||||
}
|
||||
|
||||
|
||||
private function processSubthreadRequest() : string
|
||||
{
|
||||
$mid = $_GET['mid'];
|
||||
$parent = intval($_GET['parent']);
|
||||
|
||||
$offset = null;
|
||||
if ($_GET['verb'] === 'load') {
|
||||
$offset = intval($_GET['offset']);
|
||||
}
|
||||
|
||||
$module = strip_tags($_GET['module']);
|
||||
|
||||
$items = items_by_thr_parent($mid, $parent, $offset);
|
||||
xchan_query($items);
|
||||
|
||||
$items = fetch_post_tags($items,true);
|
||||
|
||||
if ($module === 'channel') {
|
||||
$parts = explode('@', $items[0]['owner']['xchan_addr']);
|
||||
profile_load($parts[0]);
|
||||
}
|
||||
|
||||
$ret['html'] = conversation($items, $module, true, 'r_preview');
|
||||
|
||||
json_return_and_die($ret);
|
||||
}
|
||||
|
||||
public function get() : string
|
||||
{
|
||||
|
||||
if (in_array($_GET['verb'], ['comment', 'load'])) {
|
||||
return self::processSubthreadRequest();
|
||||
}
|
||||
|
||||
$verb = self::mapVerb($_GET['verb']);
|
||||
|
||||
if (!$verb) {
|
||||
killme();
|
||||
}
|
||||
|
||||
$text = get_response_button_text($_GET['verb']);
|
||||
$mid = strip_tags($_GET['mid']);
|
||||
$parent = intval($_GET['parent']);
|
||||
$observer_hash = get_observer_hash();
|
||||
|
||||
$ret['result'] = item_activity_xchans($mid, $parent, $verb);
|
||||
|
||||
$commentable = $ret['result']['is_commentable'];
|
||||
unset($ret['result']['is_commentable']);
|
||||
|
||||
if ($commentable) {
|
||||
$ret['action'] = (($verb === 'Announce') ? 'jotShare' : 'dolike');
|
||||
$ret['action_label'] = ((find_xchan_in_array($observer_hash, $ret['result'])) ? (($verb === 'Announce') ? t('+ Repeat again') : t('- Remove yours')) : t('+ Add yours'));
|
||||
}
|
||||
|
||||
$ret['title'] = $text['label'];
|
||||
|
||||
json_return_and_die($ret);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -94,7 +94,7 @@ class Rpost extends \Zotlabs\Web\Controller {
|
||||
'default_location' => $channel['channel_location'],
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'),
|
||||
'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
|
||||
'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'member/permissions'),
|
||||
'permissions' => $channel_acl,
|
||||
'bang' => '',
|
||||
'visitor' => true,
|
||||
|
||||
@@ -24,7 +24,7 @@ class Display {
|
||||
$theme = 'redbasic';
|
||||
|
||||
|
||||
$preload_images = ((x($_POST,'preload_images')) ? intval($_POST['preload_images']) : 0);
|
||||
$thread_allow = ((!empty($_POST['thread_allow'])) ? intval($_POST['thread_allow']) : 0);
|
||||
$user_scalable = ((x($_POST,'user_scalable')) ? intval($_POST['user_scalable']) : 0);
|
||||
$nosmile = ((x($_POST,'nosmile')) ? intval($_POST['nosmile']) : 0);
|
||||
$title_tosource = ((x($_POST,'title_tosource')) ? intval($_POST['title_tosource']) : 0);
|
||||
@@ -40,7 +40,7 @@ class Display {
|
||||
$itemspage = 30;
|
||||
|
||||
|
||||
set_pconfig(local_channel(),'system','preload_images',$preload_images);
|
||||
set_pconfig(local_channel(), 'system', 'thread_allow', $thread_allow);
|
||||
set_pconfig(local_channel(),'system','user_scalable',$user_scalable);
|
||||
set_pconfig(local_channel(),'system','update_interval', $browser_update);
|
||||
set_pconfig(local_channel(),'system','itemspage', $itemspage);
|
||||
@@ -146,8 +146,7 @@ class Display {
|
||||
$start_menu = get_pconfig(local_channel(), 'system', 'start_menu', 0);
|
||||
}
|
||||
|
||||
$preload_images = get_pconfig(local_channel(),'system','preload_images');
|
||||
$preload_images = (($preload_images===false)? '0': $preload_images); // default if not set: 0
|
||||
$thread_allow = get_pconfig(local_channel(), 'system', 'thread_allow', true);
|
||||
|
||||
$user_scalable = get_pconfig(local_channel(),'system','user_scalable');
|
||||
$user_scalable = (($user_scalable===false)? '0': $user_scalable); // default if not set: 0
|
||||
@@ -192,7 +191,7 @@ class Display {
|
||||
'$theme' => (($themes) ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false),
|
||||
'$schema' => (($schemas) ? array('schema', t('Select scheme'), $existing_schema, '' , $schemas) : false),
|
||||
|
||||
'$preload_images' => array('preload_images', t("Preload images before rendering the page"), $preload_images, t("The subjective page load time will be longer but the page will be ready when displayed"), $yes_no),
|
||||
'$thread_allow' => ['thread_allow', t('Threaded conversation view'), $thread_allow, t('Display replies below their parent message (default yes)'), $yes_no],
|
||||
'$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no),
|
||||
'$ajaxint' => array('browser_update', t("Update browser every xx seconds"), $browser_update, t('Minimum of 10 seconds, no maximum')),
|
||||
'$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 30 items')),
|
||||
|
||||
@@ -42,7 +42,7 @@ class Sse_bs extends Controller {
|
||||
self::$offset = 0;
|
||||
self::$xchans = '';
|
||||
|
||||
if (isset($_REQUEST['sse_rmids'])) {
|
||||
if (!empty($_REQUEST['sse_rmids'])) {
|
||||
self::mark_read(explode(',', $_REQUEST['sse_rmids']));
|
||||
}
|
||||
|
||||
@@ -118,7 +118,6 @@ class Sse_bs extends Controller {
|
||||
}
|
||||
|
||||
function mark_read($arr) {
|
||||
|
||||
$mids = [];
|
||||
$str = '';
|
||||
$slice = 0;
|
||||
@@ -142,24 +141,51 @@ class Sse_bs extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION['sse_mids_all'] = serialise($mids_all);
|
||||
$str = implode(',', $mids);
|
||||
|
||||
$sys = get_sys_channel();
|
||||
$sql_order = ((self::$uid > $sys['channel_id']) ? 'DESC' : 'ASC');
|
||||
|
||||
$r = q("SELECT uid, uuid FROM item
|
||||
WHERE uid in (%d, %d)
|
||||
AND verb IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept')
|
||||
AND thr_parent IN (
|
||||
SELECT mid FROM item WHERE uid IN (%d, %d) AND uuid IN (%s) ORDER BY uid $sql_order
|
||||
)
|
||||
GROUP BY uid, uuid
|
||||
ORDER BY uid $sql_order",
|
||||
intval(self::$uid),
|
||||
intval($sys['channel_id']),
|
||||
intval(self::$uid),
|
||||
intval($sys['channel_id']),
|
||||
$str // this is dbesc() in the above foreach loop
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$activities_str = ids_to_querystr($r, 'uuid', true);
|
||||
$str .= ',' . $activities_str;
|
||||
$activities_arr = explode(',', $activities_str);
|
||||
$mids_all = array_merge($mids_all, $activities_arr);
|
||||
}
|
||||
|
||||
$_SESSION['sse_mids_all'] = serialise(array_unique($mids_all));
|
||||
|
||||
if(! self::$uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
$str = implode(',', $mids);
|
||||
|
||||
$x = [ 'channel_id' => self::$uid, 'update' => 'unset' ];
|
||||
call_hooks('update_unseen',$x);
|
||||
|
||||
if($x['update'] === 'unset' || intval($x['update'])) {
|
||||
q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND uuid in (%s) AND item_unseen = 1",
|
||||
if ($x['update'] === 'unset' || intval($x['update'])) {
|
||||
q("UPDATE item SET item_unseen = 0
|
||||
WHERE uid = %d
|
||||
AND uuid in (%s)
|
||||
AND item_unseen = 1",
|
||||
intval(self::$uid),
|
||||
$str // this is dbesc() in the above foreach loop
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function bs_network($notifications) {
|
||||
@@ -182,32 +208,34 @@ class Sse_bs extends Controller {
|
||||
|
||||
$sql_extra = '';
|
||||
if (!(self::$vnotify & VNOTIFY_LIKE)) {
|
||||
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
$sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
elseif (!feature_enabled(self::$uid, 'dislike')) {
|
||||
$sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
$sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
|
||||
$sql_extra2 = '';
|
||||
if(self::$xchans)
|
||||
$sql_extra2 = " AND CASE WHEN verb = '" . dbesc(ACTIVITY_SHARE) . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
|
||||
$sql_extra2 = " AND CASE WHEN item.verb = '" . dbesc(ACTIVITY_SHARE) . "' THEN item.owner_xchan ELSE item.author_xchan END IN (" . self::$xchans . ") ";
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
// Filter internal follow activities and strerams add/remove activities
|
||||
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
$item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
|
||||
if ($notifications) {
|
||||
$items = q("SELECT * FROM item
|
||||
WHERE uid = %d
|
||||
AND created <= '%s'
|
||||
AND item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1)
|
||||
AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND author_xchan != '%s'
|
||||
$items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
|
||||
LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
|
||||
WHERE item.uid = %d
|
||||
AND item.created <= '%s'
|
||||
AND item.item_unseen = 1 AND item.item_wall = 0 AND item.item_private IN (0, 1)
|
||||
AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity and not the resulting item
|
||||
AND NOT item.author_xchan = '%s'
|
||||
$item_normal
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY item.created DESC LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -265,28 +293,30 @@ class Sse_bs extends Controller {
|
||||
|
||||
$sql_extra = '';
|
||||
if (!(self::$vnotify & VNOTIFY_LIKE)) {
|
||||
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
$sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
elseif (!feature_enabled(self::$uid, 'dislike')) {
|
||||
$sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
$sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
|
||||
$sql_extra2 = '';
|
||||
if(self::$xchans)
|
||||
$sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
|
||||
$sql_extra2 = " AND CASE WHEN item.verb = '" . ACTIVITY_SHARE . "' THEN item.owner_xchan ELSE item.author_xchan END IN (" . self::$xchans . ") ";
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
// Filter internal follow activities and strerams add/remove activities
|
||||
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
$item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
|
||||
if ($notifications) {
|
||||
$items = q("SELECT * FROM item
|
||||
WHERE uid = %d
|
||||
AND created <= '%s'
|
||||
AND item_unseen = 1 AND item_private = 2
|
||||
AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND author_xchan != '%s'
|
||||
$items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
|
||||
LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
|
||||
WHERE item.uid = %d
|
||||
AND item.created <= '%s'
|
||||
AND item.item_unseen = 1 AND item.item_private = 2
|
||||
AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity and not the resulting item
|
||||
AND NOT item.author_xchan = '%s'
|
||||
$item_normal
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
@@ -347,33 +377,35 @@ class Sse_bs extends Controller {
|
||||
|
||||
$sql_extra = '';
|
||||
if (!(self::$vnotify & VNOTIFY_LIKE)) {
|
||||
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
$sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
elseif (!feature_enabled(self::$uid, 'dislike')) {
|
||||
$sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
$sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
|
||||
$sql_extra2 = '';
|
||||
if(self::$xchans)
|
||||
$sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
|
||||
$sql_extra2 = " AND CASE WHEN item.verb = '" . ACTIVITY_SHARE . "' THEN item.owner_xchan ELSE item.author_xchan END IN (" . self::$xchans . ") ";
|
||||
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
// Filter internal follow activities and strerams add/remove activities
|
||||
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
$item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
|
||||
if ($notifications) {
|
||||
$items = q("SELECT * FROM item
|
||||
WHERE uid = %d
|
||||
AND created <= '%s'
|
||||
AND item_unseen = 1 AND item_wall = 1 AND item_private IN (0, 1)
|
||||
AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND author_xchan != '%s'
|
||||
$items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
|
||||
LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
|
||||
WHERE item.uid = %d
|
||||
AND item.created <= '%s'
|
||||
AND item.item_unseen = 1 AND item.item_wall = 1 AND item.item_private IN (0, 1)
|
||||
AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity and not the resulting item
|
||||
AND NOT item.author_xchan = '%s'
|
||||
$item_normal
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY item.created DESC LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -442,49 +474,51 @@ class Sse_bs extends Controller {
|
||||
$sys = get_sys_channel();
|
||||
$sql_extra = '';
|
||||
if (!(self::$vnotify & VNOTIFY_LIKE)) {
|
||||
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
$sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
elseif (!feature_enabled(self::$uid, 'dislike')) {
|
||||
$sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
$sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
|
||||
$sql_extra2 = '';
|
||||
if(self::$xchans)
|
||||
$sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
|
||||
$sql_extra2 = " AND CASE WHEN item.verb = '" . ACTIVITY_SHARE . "' THEN item.owner_xchan ELSE item.author_xchan END IN (" . self::$xchans . ") ";
|
||||
|
||||
$sql_extra3 = '';
|
||||
$sse_mids_all = unserialise($_SESSION['sse_mids_all']) ?? [];
|
||||
$sse_mids_all = isset($_SESSION['sse_mids_all']) ? unserialise($_SESSION['sse_mids_all']) : [];
|
||||
if ($sse_mids_all) {
|
||||
$sql_extra3 = " AND uuid NOT IN (" . protect_sprintf(implode(',', $sse_mids_all)) . ") ";
|
||||
$sql_extra3 = " AND item.uuid NOT IN (" . protect_sprintf(implode(',', $sse_mids_all)) . ") ";
|
||||
}
|
||||
|
||||
$uids = " AND uid IN ( " . $sys['channel_id'] . " ) ";
|
||||
$uids = " AND item.uid IN ( " . $sys['channel_id'] . " ) ";
|
||||
|
||||
$site_firehose = Config::Get('system', 'site_firehose', 0);
|
||||
if($site_firehose) {
|
||||
$uids = " AND uid IN ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) AND item_private = 0 AND item_wall = 1 ";
|
||||
$uids = " AND item.uid IN ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) AND item.item_private = 0 AND item.item_wall = 1 ";
|
||||
}
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
// Filter internal follow activities and strerams add/remove activities
|
||||
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
$item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
|
||||
if ($notifications) {
|
||||
$items = q("SELECT * FROM item
|
||||
$items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
|
||||
LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
|
||||
WHERE true $uids
|
||||
AND created <= '%s'
|
||||
AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND author_xchan != '%s'
|
||||
AND created > '%s'
|
||||
AND item.created <= '%s'
|
||||
AND item.created > '%s'
|
||||
AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity not the resulting item
|
||||
AND NOT item.author_xchan = '%s'
|
||||
$item_normal
|
||||
$sql_extra
|
||||
$sql_extra2
|
||||
$sql_extra3
|
||||
ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY item.created DESC LIMIT $limit OFFSET $offset",
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash),
|
||||
dbescdate($_SESSION['last_login_date'] ?? $_SESSION['static_loadtime'])
|
||||
dbescdate($_SESSION['last_login_date'] ?? $_SESSION['static_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
);
|
||||
|
||||
if($items) {
|
||||
@@ -602,25 +636,15 @@ class Sse_bs extends Controller {
|
||||
$i = 0;
|
||||
|
||||
for($x = 0; $x < $fcount; $x ++) {
|
||||
/*
|
||||
$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
|
||||
intval(self::$uid),
|
||||
intval(TERM_FORUM),
|
||||
dbesc($forums[$x]['xchan_name'])
|
||||
);
|
||||
|
||||
$p_str = ids_to_querystr($p, 'parent');
|
||||
$p_sql = (($p_str) ? "OR parent IN ( $p_str )" : '');
|
||||
*/
|
||||
|
||||
$r = q("select count(*) as total from item
|
||||
where uid = %d and ( owner_xchan = '%s' OR author_xchan = '%s' $p_sql ) and verb != 'Announce' and item_unseen = 1 $sql_extra $item_normal",
|
||||
where uid = %d and (owner_xchan = '%s' or author_xchan = '%s') and author_xchan != '%s' and verb != 'Announce' and item_unseen = 1 $sql_extra $item_normal",
|
||||
intval(self::$uid),
|
||||
dbesc($forums[$x]['xchan_hash']),
|
||||
dbesc($forums[$x]['xchan_hash'])
|
||||
dbesc($forums[$x]['xchan_hash']),
|
||||
dbesc(self::$ob_hash)
|
||||
);
|
||||
|
||||
|
||||
if($r[0]['total']) {
|
||||
|
||||
$forums[$x]['notify_link'] = z_root() . '/network/?f=&pf=1&unseen=1&cid=' . $forums[$x]['abook_id'];
|
||||
|
||||
@@ -6,34 +6,34 @@ namespace Zotlabs\Module;
|
||||
class Viewsrc extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
|
||||
$o = '';
|
||||
|
||||
|
||||
$sys = get_sys_channel();
|
||||
|
||||
|
||||
$item_id = ((argc() > 1) ? intval(argv(1)) : 0);
|
||||
$json = ((argc() > 2 && argv(2) === 'json') ? true : false);
|
||||
$dload = ((argc() > 2 && argv(2) === 'download') ? true : false);
|
||||
|
||||
|
||||
if(! local_channel()) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if(! $item_id) {
|
||||
\App::$error = 404;
|
||||
notice( t('Item not found.') . EOL);
|
||||
}
|
||||
|
||||
|
||||
$item_normal = item_normal_search();
|
||||
|
||||
|
||||
if(local_channel() && $item_id) {
|
||||
$r = q("select id, mid, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1",
|
||||
$r = q("select id, mid, uuid, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1",
|
||||
intval(local_channel()),
|
||||
intval($sys['channel_id']),
|
||||
intval($item_id)
|
||||
);
|
||||
|
||||
|
||||
if($r) {
|
||||
if(intval($r[0]['item_obscured']))
|
||||
$dload = true;
|
||||
@@ -50,18 +50,18 @@ class Viewsrc extends \Zotlabs\Web\Controller {
|
||||
$o = (($json) ? json_encode($content) : $content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(is_ajax()) {
|
||||
echo '<div class="p-1">';
|
||||
echo '<div>id: ' . $r[0]['id'] . ' | <a href="' . $r[0]['plink'] . '" target="_blank">plink</a> | <a href="' . $r[0]['llink'] . '" target="_blank">llink</a><br>mid: ' . $r[0]['mid'] . '</div>';
|
||||
echo '<div>id: ' . $r[0]['id'] . ' | <a href="' . $r[0]['plink'] . '" target="_blank">plink</a> | <a href="' . $r[0]['llink'] . '" target="_blank">llink</a><br>mid: ' . $r[0]['mid'] . '<br>uuid: ' . $r[0]['uuid'] . '</div>';
|
||||
echo '<hr>';
|
||||
echo '<pre class="p-1">' . $o . '</pre>';
|
||||
echo '</div>';
|
||||
killme();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class Wall_attach extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
logger('request_method: ' . $_SERVER['REQUEST_METHOD'],LOGGER_DATA,LOG_INFO);
|
||||
logger('wall_attach: ' . print_r($_REQUEST,true),LOGGER_DEBUG,LOG_INFO);
|
||||
logger('wall_attach: ' . print_r($_POST,true),LOGGER_DEBUG,LOG_INFO);
|
||||
logger('wall_attach files: ' . print_r($_FILES,true),LOGGER_DEBUG,LOG_INFO);
|
||||
// for testing without actually storing anything
|
||||
// http_status_exit(200,'OK');
|
||||
@@ -18,12 +18,11 @@ class Wall_attach extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
function post() {
|
||||
|
||||
$using_api = false;
|
||||
|
||||
$result = [];
|
||||
|
||||
if($_REQUEST['api_source'] && array_key_exists('media',$_FILES)) {
|
||||
if($_POST['api_source'] && array_key_exists('media',$_FILES)) {
|
||||
$using_api = true;
|
||||
}
|
||||
|
||||
@@ -98,8 +97,8 @@ class Wall_attach extends \Zotlabs\Web\Controller {
|
||||
|
||||
$r = attach_store($channel, get_observer_hash(), '', $data);
|
||||
|
||||
if(! $r['success']) {
|
||||
notice( $r['message'] . EOL);
|
||||
if (!$r['success']) {
|
||||
notice($r['message'] . EOL);
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
|
||||
class Xref extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
// Sets a referral URL using an xchan directly
|
||||
// Link format: example.com/xref/[xchan]/[TargetURL]
|
||||
// Target URL is optional.
|
||||
// Cookie lasts 24 hours to survive a browser restart. Contains no personal
|
||||
// information at all - just somebody else's xchan.
|
||||
$referrer = argv(1);
|
||||
$expire=time()+60*60*2;
|
||||
$path = 'xref';
|
||||
setcookie($path, $referrer, $expire, "/");
|
||||
$url = '';
|
||||
|
||||
if (argc() > 2)
|
||||
$url = argv(2);
|
||||
|
||||
goaway (z_root() . '/' . $url);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,19 +9,29 @@ class Zot_probe extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
if (!local_channel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$addr = $_GET['addr'] ?? '';
|
||||
|
||||
$o = '<h3>Zot6 Probe Diagnostic</h3>';
|
||||
|
||||
$o .= '<form action="zot_probe" method="get">';
|
||||
$o .= 'Lookup URI: <input type="text" style="width: 250px;" name="addr" value="' . $addr .'" /><br>';
|
||||
$o .= '<input type="checkbox" name="sign" /> Sign request <br>';
|
||||
$o .= '<input type="submit" name="submit" value="Submit" /></form>';
|
||||
|
||||
$o .= '<br /><br />';
|
||||
|
||||
if($addr) {
|
||||
|
||||
$x = Zotfinger::exec($addr);
|
||||
$channel = null;
|
||||
if ($_GET['sign']) {
|
||||
$channel = get_sys_channel();
|
||||
}
|
||||
|
||||
$x = Zotfinger::exec($addr, $channel);
|
||||
|
||||
$o .= '<pre>' . htmlspecialchars(print_array($x)) . '</pre>';
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ class PhotoGd extends PhotoDriver {
|
||||
$t['image/gif'] = 'gif';
|
||||
if(\imagetypes() & IMG_WEBP)
|
||||
$t['image/webp'] = 'webp';
|
||||
if(\imagetypes() & IMG_AVIF)
|
||||
$t['image/avif'] = 'avif';
|
||||
|
||||
return $t;
|
||||
}
|
||||
@@ -184,6 +186,19 @@ class PhotoGd extends PhotoDriver {
|
||||
|
||||
break;
|
||||
|
||||
case 'image/avif':
|
||||
$quality = Config::Get('system', 'avif_quality');
|
||||
|
||||
if((! $quality) || ($quality > 100)) {
|
||||
$quality = AVIF_QUALITY;
|
||||
}
|
||||
|
||||
if (function_exists('imageavif')) {
|
||||
\imageavif($this->image, NULL, $quality);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'image/jpeg':
|
||||
// gd can lack imagejpeg(), but we verify during installation it is available
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Render;
|
||||
|
||||
use Smarty;
|
||||
use Smarty\Smarty;
|
||||
use App;
|
||||
|
||||
class SmartyInterface extends Smarty {
|
||||
@@ -19,20 +19,20 @@ class SmartyInterface extends Smarty {
|
||||
// The order is thus very important here
|
||||
|
||||
$template_dirs = array('theme' => "view/theme/$thname/tpl/");
|
||||
if ( x(App::$theme_info,"extends") ) {
|
||||
if (!empty(App::$theme_info['extends'])) {
|
||||
$template_dirs = $template_dirs + array('extends' => "view/theme/" . App::$theme_info["extends"] . "/tpl/");
|
||||
}
|
||||
$template_dirs = $template_dirs + array('base' => 'view/tpl/');
|
||||
$this->setTemplateDir($template_dirs);
|
||||
|
||||
$basecompiledir = App::$config['system']['smarty3_folder'];
|
||||
|
||||
|
||||
$this->setCompileDir($basecompiledir.'/compiled/');
|
||||
$this->setConfigDir($basecompiledir.'/config/');
|
||||
$this->setCacheDir($basecompiledir.'/cache/');
|
||||
|
||||
$this->left_delimiter = App::get_template_ldelim('smarty3');
|
||||
$this->right_delimiter = App::get_template_rdelim('smarty3');
|
||||
$this->setLeftDelimiter(App::get_template_ldelim('smarty3'));
|
||||
$this->setRightDelimiter(App::get_template_rdelim('smarty3'));
|
||||
|
||||
// Don't report errors so verbosely
|
||||
$this->error_reporting = E_ALL & ~E_WARNING & ~E_NOTICE;
|
||||
|
||||
@@ -26,9 +26,9 @@ class Theme {
|
||||
*/
|
||||
static public function current() {
|
||||
|
||||
self::$system_theme = ((isset(App::$config['system']['theme']))
|
||||
self::$system_theme = ((!empty(App::$config['system']['theme']))
|
||||
? App::$config['system']['theme'] : '');
|
||||
self::$session_theme = ((isset($_SESSION) && x($_SESSION, 'theme'))
|
||||
self::$session_theme = ((!empty($_SESSION['theme']))
|
||||
? $_SESSION['theme'] : self::$system_theme);
|
||||
|
||||
$page_theme = null;
|
||||
@@ -87,8 +87,13 @@ class Theme {
|
||||
// Find any theme at all and use it.
|
||||
|
||||
$fallback = array_merge(glob('view/theme/*/css/style.css'), glob('view/theme/*/php/style.php'));
|
||||
if(count($fallback))
|
||||
return(array(str_replace('view/theme/', '', substr($fallback[0], 0, -14))));
|
||||
|
||||
if (empty($fallback)) {
|
||||
logger('Unable to find a theme');
|
||||
http_status_exit(500, 'internal server error');
|
||||
}
|
||||
|
||||
return(array(str_replace('view/theme/', '', substr($fallback[0], 0, -14))));
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +116,7 @@ class Theme {
|
||||
$opts = '';
|
||||
$opts = (($uid) ? '?puid=' . $uid : '');
|
||||
|
||||
$schema_str = ((x(App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
|
||||
$schema_str = ((!empty(App::$layout['schema'])) ? '&schema=' . App::$layout['schema'] : '');
|
||||
if(($s) && (! $schema_str))
|
||||
$schema_str = '&schema=' . $s;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Zotlabs\Storage;
|
||||
use Sabre\DAV;
|
||||
use App;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Text;
|
||||
|
||||
/**
|
||||
* @brief Provides a DAV frontend for the webbrowser.
|
||||
@@ -260,13 +261,16 @@ class Browser extends DAV\Browser\Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
$display_path_encoded = Text::rawurlencode_parts($data['display_path']);
|
||||
$href_encoded = Text::rawurlencode_parts($href);
|
||||
|
||||
// put the array for this file together
|
||||
$ft['attach_id'] = $id;
|
||||
// $ft['icon'] = $icon;
|
||||
$ft['photo_icon'] = $photo_icon;
|
||||
$ft['is_creator'] = $is_creator;
|
||||
$ft['rel_path'] = (($data) ? '/cloud/' . $nick .'/' . $data['display_path'] : $href);
|
||||
$ft['full_path'] = z_root() . (($data) ? '/cloud/' . $nick .'/' . $data['display_path'] : $href);
|
||||
$ft['rel_path'] = (($data) ? '/cloud/' . $nick .'/' . $display_path_encoded : $href_encoded);
|
||||
$ft['full_path'] = z_root() . (($data) ? '/cloud/' . $nick .'/' . $display_path_encoded : $href_encoded);
|
||||
$ft['name'] = $name;
|
||||
$ft['type'] = $type;
|
||||
$ft['size'] = $size;
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
namespace Zotlabs\Thumbs;
|
||||
|
||||
use SebLucas\EPubMeta\EPub;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use DOMXPath;
|
||||
use GdImage;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
* Thumbnail creation for epub files.
|
||||
@@ -24,20 +27,21 @@ class Epubthumb {
|
||||
* Create the thumbnail if the Epub has a cover.
|
||||
*
|
||||
* @param array $attach
|
||||
* @param number $preview_style unused
|
||||
* @param number $height (optional) default 300
|
||||
* @param number $width (optional) default 300
|
||||
* @param int $preview_style unused
|
||||
* @param int $height (optional) default 300
|
||||
* @param int $width (optional) default 300
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
*/
|
||||
function Thumb($attach, $preview_style, $height = 300, $width = 300) {
|
||||
function Thumb($attach, $preview_style, $height = 300, $width = 300): void {
|
||||
|
||||
$file = dbunescbin($attach['content']);
|
||||
if (!$file) {
|
||||
return;
|
||||
}
|
||||
|
||||
$image = $this->getCover($file);
|
||||
$image = $this->getCoverFromEpub($file);
|
||||
|
||||
if ($image) {
|
||||
$srcwidth = imagesx($image);
|
||||
@@ -56,15 +60,139 @@ class Epubthumb {
|
||||
}
|
||||
}
|
||||
|
||||
private function getCover(string $filename): GdImage|false {
|
||||
$epub = new EPub($filename);
|
||||
$cover = $epub->getCover();
|
||||
/**
|
||||
* Fetch the cover from the epub archive, if it's present.
|
||||
*
|
||||
* There's a few limitations here: This will only work if the cover
|
||||
* is a raster image of a supported format. SVG does not work, neither
|
||||
* will other schemes sometimes used for cover/front page.
|
||||
*
|
||||
* @param string $filename The local filename of the epub archive.
|
||||
*
|
||||
* @return GdImage|false If a cover is found, it is returned as a
|
||||
* GdImage object. Otherwise return false.
|
||||
*/
|
||||
private function getCoverFromEpub(string $filename): GdImage|false {
|
||||
$epub = new ZipArchive();
|
||||
$rc = $epub->open($filename, ZipArchive::RDONLY);
|
||||
|
||||
if (! empty($cover)) {
|
||||
if ($rc !== true) {
|
||||
logger("Error opening file '{$filename}': rc = ${rc}.", LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cover = false;
|
||||
$cover_name = $this->parseEpub($epub);
|
||||
if ($cover_name !== false) {
|
||||
$cover = $epub->getFromName($cover_name);
|
||||
if ($cover === false) {
|
||||
logger("File '{$cover_name}' not found in EPUB.", LOGGER_DEBUG, LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
$epub->close();
|
||||
|
||||
if ($cover !== false && !empty($cover)) {
|
||||
return imagecreatefromstring($cover);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the epub to find the path of the cover image.
|
||||
*
|
||||
* @param ZipArchive $epub An opened epub ZipArchive.
|
||||
*
|
||||
* @return string|false The path to the cover image or false.
|
||||
*/
|
||||
private function parseEpub(ZipArchive $epub): string|false {
|
||||
$packagePath = $this->getEpubPackagePath($epub);
|
||||
if ($packagePath !== false) {
|
||||
$package = $epub->getFromName($packagePath);
|
||||
if ($package === false || empty($package)) {
|
||||
logger("Package file '${packagePath}' not found in EPUB", LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$domdoc = new DOMDocument();
|
||||
$domdoc->loadXML($package);
|
||||
$xpath = new DOMXPath($domdoc);
|
||||
$xpath->registerNamespace("n", "http://www.idpf.org/2007/opf");
|
||||
$nodes = $xpath->query('/n:package/n:manifest/n:item[@properties="cover-image"]');
|
||||
|
||||
if ($nodes->count() === 0) {
|
||||
logger('No cover found in EPUB manifest.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$node = $nodes->item(0);
|
||||
if ($node === null) {
|
||||
logger('No nodes in non-empty node list?', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_a($node, DOMElement::class)) {
|
||||
// The URL's in the package file is relative to the subdirectory
|
||||
// within the epub archive where it is located. See
|
||||
// https://www.w3.org/TR/epub-33/#sec-parsing-urls-metainf
|
||||
return dirname($packagePath) . '/' . $node->getAttribute('href');
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the package file within the epub.
|
||||
*
|
||||
* The package file in an epub archive contains the manifest
|
||||
* that again may contain a reference to the cover for the
|
||||
* epub.
|
||||
*
|
||||
* @param ZipArchive $epub An opened epub archive.
|
||||
*
|
||||
* @return string|false The full pathname of the package file or false.
|
||||
*/
|
||||
private function getEpubPackagePath(ZipArchive $epub): string|false {
|
||||
//
|
||||
// The only mandatory known file within the archive is the
|
||||
// container file, so we fetch it to find the reference to
|
||||
// the package file.
|
||||
//
|
||||
// See: https://www.w3.org/TR/epub-33/#sec-container-metainf
|
||||
//
|
||||
$container = $epub->getFromName('META-INF/container.xml');
|
||||
|
||||
if ($container === false || empty($container)) {
|
||||
logger('No container in archive, probably not an EPUB.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$domdoc = new DOMDocument();
|
||||
$domdoc->loadXML($container);
|
||||
$nodes = $domdoc->getElementsByTagName('rootfile');
|
||||
|
||||
if ($nodes->count() == 0) {
|
||||
logger('EPUB rootfile not found, is this an epub?', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$packageNode = $nodes->item(0);
|
||||
if ($packageNode === null || !is_a($packageNode, DOMElement::class)) {
|
||||
logger('EPUB rootfile element missing or invalid.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$packagePath = $packageNode->getAttribute('full-path');
|
||||
$packageMediaType = $packageNode->getAttribute('media-type');
|
||||
|
||||
if (empty($packagePath) || $packageMediaType !== 'application/oebps-package+xml') {
|
||||
logger('EPUB package path missing or incorrect media type.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $packagePath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Web;
|
||||
|
||||
use App;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use Zotlabs\Lib\Activity;
|
||||
@@ -11,6 +12,9 @@ use Zotlabs\Lib\Keyutils;
|
||||
use Zotlabs\Lib\Webfinger;
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use HttpSignature\HttpMessageSigner;
|
||||
use HttpSignature\UnProcessableSignatureException;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-10.
|
||||
@@ -88,7 +92,7 @@ class HTTPSig {
|
||||
|
||||
// See draft-cavage-http-signatures-10
|
||||
|
||||
static function verify($data, $key = '', $keytype = '') {
|
||||
public static function verify($data, $key = '', $keytype = '') {
|
||||
|
||||
$body = $data;
|
||||
$headers = null;
|
||||
@@ -102,11 +106,59 @@ class HTTPSig {
|
||||
'content_valid' => false
|
||||
];
|
||||
|
||||
|
||||
$headers = self::find_headers($data, $body);
|
||||
|
||||
if (!$headers)
|
||||
if (!$headers) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (App::$request && array_key_exists('signature-input', $headers) && array_key_exists('signature', $headers)) {
|
||||
$found = preg_match('/keyid="(.*?)"/', $headers['signature-input'], $matches);
|
||||
$keyId = ($found) ? $matches[1] : '';
|
||||
|
||||
if (!$keyId) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$found = preg_match('/alg="(.*?)"/', $headers['signature-input'], $matches);
|
||||
$alg = ($found) ? $matches[1] : null;
|
||||
|
||||
$keyInfo = self::get_key($key, $keytype, $keyId);
|
||||
$publicKey = $keyInfo['public_key'];
|
||||
|
||||
$messageSigner = new HttpMessageSigner();
|
||||
|
||||
$messageSigner->setPublicKey($publicKey);
|
||||
$messageSigner->setAlgorithm($alg);
|
||||
$messageSigner->setKeyId($keyId);
|
||||
|
||||
$messageSigner->setNonce(preg_match('/nonce="(.*?)"/', $headers['signature-input'], $matches) ? $matches[1] : '');
|
||||
$messageSigner->setTag(preg_match('/tag="(.*?)"/', $headers['signature-input'], $matches) ? $matches[1] : '');
|
||||
$messageSigner->setCreated(preg_match('/created=([0-9]+)/', $headers['signature-input'], $matches) ? $matches[1] : '');
|
||||
$messageSigner->setExpires(preg_match('/expires=([0-9]+)/', $headers['signature-input'], $matches) ? $matches[1] : '');
|
||||
|
||||
try {
|
||||
$verified = $messageSigner->verifyRequest(App::$request);
|
||||
if (!$verified) {
|
||||
btlogger('RFC9421: Unable to verify request: ' . print_r($headers, true), LOGGER_DATA);
|
||||
}
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
btlogger($exception->getMessage(), LOGGER_DATA);
|
||||
$verified = false;
|
||||
}
|
||||
|
||||
logger('verified (RFC9421): ' . (($verified) ? 'true' : 'false'), LOGGER_DEBUG);
|
||||
|
||||
return [
|
||||
'signer' => $keyId,
|
||||
'portable_id' => $keyInfo['portable_id'] ?? '',
|
||||
'header_signed' => true,
|
||||
'header_valid' => $verified,
|
||||
'content_signed' => array_key_exists('content-digest', $headers),
|
||||
'content_valid' => $verified
|
||||
];
|
||||
}
|
||||
|
||||
if (is_array($body)) {
|
||||
btlogger('body is array:' . print_r($body, true));
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Zotlabs\Web;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Extend\Route;
|
||||
use Zotlabs\Render\Theme;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Exception;
|
||||
|
||||
@@ -33,6 +34,7 @@ use Exception;
|
||||
* so within the module init and/or post functions and then invoke killme() to terminate
|
||||
* further processing.
|
||||
*/
|
||||
|
||||
class Router {
|
||||
|
||||
private $modname = '';
|
||||
@@ -49,7 +51,7 @@ class Router {
|
||||
$module = App::$module;
|
||||
$modname = "Zotlabs\\Module\\" . ucfirst($module);
|
||||
|
||||
if(strlen($module)) {
|
||||
if(!empty($module)) {
|
||||
|
||||
/*
|
||||
* We will always have a module name.
|
||||
@@ -57,11 +59,11 @@ class Router {
|
||||
*/
|
||||
|
||||
$routes = Route::get();
|
||||
if($routes) {
|
||||
if ($routes) {
|
||||
foreach($routes as $route) {
|
||||
if(is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
|
||||
if (is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
|
||||
include_once($route[0]);
|
||||
if(class_exists($modname)) {
|
||||
if (class_exists($modname)) {
|
||||
$this->controller = new $modname;
|
||||
$this->module_loaded = true;
|
||||
}
|
||||
@@ -71,14 +73,14 @@ class Router {
|
||||
|
||||
// legacy plugins - this can be removed when they have all been converted
|
||||
|
||||
if(! ($this->module_loaded)) {
|
||||
if(is_array(App::$plugins) && in_array($module, App::$plugins) && file_exists("addon/{$module}/{$module}.php")) {
|
||||
if (!$this->module_loaded) {
|
||||
if (is_array(App::$plugins) && in_array($module, App::$plugins) && file_exists("addon/{$module}/{$module}.php")) {
|
||||
include_once("addon/{$module}/{$module}.php");
|
||||
if(class_exists($modname)) {
|
||||
if (class_exists($modname)) {
|
||||
$this->controller = new $modname;
|
||||
$this->module_loaded = true;
|
||||
}
|
||||
elseif(function_exists($module . '_module')) {
|
||||
elseif (function_exists($module . '_module')) {
|
||||
$this->module_loaded = true;
|
||||
}
|
||||
}
|
||||
@@ -89,7 +91,7 @@ class Router {
|
||||
* Otherwise, look for the standard program module
|
||||
*/
|
||||
|
||||
if(! ($this->module_loaded)) {
|
||||
if (!$this->module_loaded) {
|
||||
try {
|
||||
$filename = 'Zotlabs/SiteModule/'. ucfirst($module). '.php';
|
||||
if(file_exists($filename)) {
|
||||
@@ -105,15 +107,16 @@ class Router {
|
||||
$this->module_loaded = true;
|
||||
}
|
||||
}
|
||||
if(! $this->module_loaded)
|
||||
if (!$this->module_loaded) {
|
||||
throw new Exception('Module not found');
|
||||
}
|
||||
}
|
||||
catch(Exception $e) {
|
||||
if(file_exists("mod/site/{$module}.php")) {
|
||||
catch (Exception $e) {
|
||||
if (file_exists("mod/site/{$module}.php")) {
|
||||
include_once("mod/site/{$module}.php");
|
||||
$this->module_loaded = true;
|
||||
}
|
||||
elseif(file_exists("mod/{$module}.php")) {
|
||||
elseif (file_exists("mod/{$module}.php")) {
|
||||
include_once("mod/{$module}.php");
|
||||
$this->module_loaded = true;
|
||||
}
|
||||
@@ -125,6 +128,7 @@ class Router {
|
||||
'installed' => $this->module_loaded,
|
||||
'controller' => $this->controller
|
||||
];
|
||||
|
||||
/**
|
||||
* @hooks module_loaded
|
||||
* Called when a module has been successfully locate to server a URL request.
|
||||
@@ -138,7 +142,8 @@ class Router {
|
||||
* * \e mixed \b controller - The initialized module object
|
||||
*/
|
||||
call_hooks('module_loaded', $x);
|
||||
if($x['installed']) {
|
||||
|
||||
if ($x['installed']) {
|
||||
$this->module_loaded = true;
|
||||
$this->controller = $x['controller'];
|
||||
}
|
||||
@@ -147,7 +152,7 @@ class Router {
|
||||
* The URL provided does not resolve to a valid module.
|
||||
*/
|
||||
|
||||
if(! ($this->module_loaded)) {
|
||||
if (!$this->module_loaded) {
|
||||
|
||||
// undo the setting of a letsencrypt acme-challenge rewrite rule
|
||||
// which blocks access to our .well-known routes.
|
||||
@@ -155,8 +160,8 @@ class Router {
|
||||
// for a custom .htaccess in the .well-known directory; but they should
|
||||
// make the file read-only so letsencrypt doesn't modify it
|
||||
|
||||
if(strpos($_SERVER['REQUEST_URI'],'/.well-known/') === 0) {
|
||||
if(file_exists('.well-known/.htaccess') && Config::Get('system','fix_apache_acme',true)) {
|
||||
if (strpos($_SERVER['REQUEST_URI'],'/.well-known/') === 0) {
|
||||
if (file_exists('.well-known/.htaccess') && Config::Get('system','fix_apache_acme',true)) {
|
||||
rename('.well-known/.htaccess','.well-known/.htaccess.old');
|
||||
}
|
||||
}
|
||||
@@ -166,16 +171,17 @@ class Router {
|
||||
'installed' => $this->module_loaded,
|
||||
'controller' => $this->controller
|
||||
];
|
||||
|
||||
call_hooks('page_not_found',$x);
|
||||
|
||||
// Stupid browser tried to pre-fetch our Javascript img template.
|
||||
// Don't log the event or return anything - just quietly exit.
|
||||
|
||||
if((x($_SERVER, 'QUERY_STRING')) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
|
||||
if (!empty($_SERVER['QUERY_STRING']) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
|
||||
killme();
|
||||
}
|
||||
|
||||
if(Config::Get('system','log_404',true)) {
|
||||
if (Config::Get('system','log_404',true)) {
|
||||
logger("Module {$module} not found.", LOGGER_DEBUG, LOG_WARNING);
|
||||
logger('index.php: page not found: ' . $_SERVER['REQUEST_URI']
|
||||
. ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: '
|
||||
@@ -206,7 +212,7 @@ class Router {
|
||||
* Call module functions
|
||||
*/
|
||||
|
||||
if($this->module_loaded) {
|
||||
if ($this->module_loaded) {
|
||||
|
||||
App::$page['page_title'] = App::$module;
|
||||
$placeholder = '';
|
||||
@@ -218,13 +224,18 @@ class Router {
|
||||
* to over-ride them.
|
||||
*/
|
||||
|
||||
$arr = array('init' => true, 'replace' => false);
|
||||
$arr = [
|
||||
'init' => true,
|
||||
'replace' => false
|
||||
];
|
||||
|
||||
call_hooks(App::$module . '_mod_init', $arr);
|
||||
if(! $arr['replace']) {
|
||||
if($this->controller && method_exists($this->controller,'init')) {
|
||||
|
||||
if (!$arr['replace']) {
|
||||
if ($this->controller && method_exists($this->controller,'init')) {
|
||||
$this->controller->init();
|
||||
}
|
||||
elseif(function_exists(App::$module . '_init')) {
|
||||
elseif (function_exists(App::$module . '_init')) {
|
||||
$func = App::$module . '_init';
|
||||
$func();
|
||||
}
|
||||
@@ -250,52 +261,58 @@ class Router {
|
||||
* load current theme info
|
||||
*/
|
||||
|
||||
$current_theme = \Zotlabs\Render\Theme::current();
|
||||
$current_theme = Theme::current();
|
||||
|
||||
$theme_info_file = 'view/theme/' . $current_theme[0] . '/php/theme.php';
|
||||
if (file_exists($theme_info_file)){
|
||||
require_once($theme_info_file);
|
||||
}
|
||||
|
||||
if(function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) {
|
||||
if (function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) {
|
||||
$func = str_replace('-', '_', $current_theme[0]) . '_init';
|
||||
$func();
|
||||
}
|
||||
elseif (x(App::$theme_info, 'extends') && file_exists('view/theme/' . App::$theme_info['extends'] . '/php/theme.php')) {
|
||||
elseif (!empty(App::$theme_info['extends']) && file_exists('view/theme/' . App::$theme_info['extends'] . '/php/theme.php')) {
|
||||
require_once('view/theme/' . App::$theme_info['extends'] . '/php/theme.php');
|
||||
if(function_exists(str_replace('-', '_', App::$theme_info['extends']) . '_init')) {
|
||||
if (function_exists(str_replace('-', '_', App::$theme_info['extends']) . '_init')) {
|
||||
$func = str_replace('-', '_', App::$theme_info['extends']) . '_init';
|
||||
$func();
|
||||
}
|
||||
}
|
||||
|
||||
if(($_SERVER['REQUEST_METHOD'] === 'POST') && (! App::$error) && (! x($_POST, 'auth-params'))) {
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !App::$error && empty($_POST['auth-params'])) {
|
||||
call_hooks(App::$module . '_mod_post', $_POST);
|
||||
|
||||
if($this->controller && method_exists($this->controller,'post')) {
|
||||
if ($this->controller && method_exists($this->controller, 'post')) {
|
||||
$this->controller->post();
|
||||
}
|
||||
elseif(function_exists(App::$module . '_post')) {
|
||||
elseif (function_exists(App::$module . '_post')) {
|
||||
$func = App::$module . '_post';
|
||||
$func();
|
||||
}
|
||||
}
|
||||
|
||||
if(! App::$error) {
|
||||
$arr = array('content' => App::$page['content'], 'replace' => false);
|
||||
if (!App::$error) {
|
||||
$arr = [
|
||||
'content' => App::$page['content'],
|
||||
'replace' => false
|
||||
];
|
||||
|
||||
call_hooks(App::$module . '_mod_content', $arr);
|
||||
|
||||
if(! $arr['replace']) {
|
||||
if($this->controller && method_exists($this->controller,'get')) {
|
||||
if (!$arr['replace']) {
|
||||
if ($this->controller && method_exists($this->controller, 'get')) {
|
||||
$arr = array('content' => $this->controller->get());
|
||||
}
|
||||
elseif(function_exists(App::$module . '_content')) {
|
||||
elseif (function_exists(App::$module . '_content')) {
|
||||
$func = App::$module . '_content';
|
||||
$arr = array('content' => $func());
|
||||
}
|
||||
}
|
||||
|
||||
call_hooks(App::$module . '_mod_aftercontent', $arr);
|
||||
App::$page['content'] = ((isset($arr['replace'])) ? $arr['content'] : App::$page['content'] . $arr['content']);
|
||||
|
||||
App::$page['content'] = ((empty($arr['replace'])) ? App::$page['content'] . $arr['content'] : $arr['content']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ class Session {
|
||||
else
|
||||
logger('no session handler');
|
||||
|
||||
if (x($_COOKIE, 'jsdisabled')) {
|
||||
if (!empty($_COOKIE['jsdisabled'])) {
|
||||
setcookie(
|
||||
'jsdisabled',
|
||||
$_COOKIE['jsdisabled'],
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
namespace Zotlabs\Web;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Lib\Text;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
|
||||
|
||||
class WebServer {
|
||||
|
||||
@@ -17,9 +20,10 @@ class WebServer {
|
||||
|
||||
$installed = sys_boot();
|
||||
|
||||
$this->createRequest();
|
||||
|
||||
\App::$language = get_best_language();
|
||||
load_translation_table(\App::$language, !$installed);
|
||||
App::$language = get_best_language();
|
||||
load_translation_table(App::$language, !$installed);
|
||||
|
||||
|
||||
/**
|
||||
@@ -33,8 +37,8 @@ class WebServer {
|
||||
*
|
||||
*/
|
||||
|
||||
if(\App::$session) {
|
||||
\App::$session->start();
|
||||
if(App::$session) {
|
||||
App::$session->start();
|
||||
}
|
||||
else {
|
||||
session_start();
|
||||
@@ -53,13 +57,13 @@ class WebServer {
|
||||
unset($_SESSION['language']);
|
||||
}
|
||||
|
||||
if ((x($_SESSION, 'language')) && ($_SESSION['language'] !== \App::$language)) {
|
||||
\App::$language = $_SESSION['language'];
|
||||
if ((!empty($_SESSION['language'])) && ($_SESSION['language'] !== App::$language)) {
|
||||
App::$language = $_SESSION['language'];
|
||||
load_translation_table(\App::$language);
|
||||
}
|
||||
|
||||
if (x($_GET,'zid') && $installed) {
|
||||
\App::$query_string = strip_zids(\App::$query_string);
|
||||
if (!empty($_GET['zid']) && $installed) {
|
||||
App::$query_string = strip_zids(App::$query_string);
|
||||
if(! local_channel()) {
|
||||
if (!isset($_SESSION['my_address'])) {
|
||||
$_SESSION['my_address'] = Text::escape_tags($_GET['zid']);
|
||||
@@ -71,26 +75,28 @@ class WebServer {
|
||||
}
|
||||
}
|
||||
|
||||
if (x($_GET,'zat') && $installed) {
|
||||
\App::$query_string = strip_zats(\App::$query_string);
|
||||
if (!empty($_GET['zat']) && $installed) {
|
||||
App::$query_string = strip_zats(App::$query_string);
|
||||
if(! local_channel()) {
|
||||
zat_init();
|
||||
}
|
||||
}
|
||||
|
||||
if (x($_REQUEST,'owt') && $installed) {
|
||||
if (!empty($_REQUEST['owt']) && $installed) {
|
||||
$token = $_REQUEST['owt'];
|
||||
\App::$query_string = strip_query_param(\App::$query_string,'owt');
|
||||
App::$query_string = strip_query_param(App::$query_string,'owt');
|
||||
owt_init($token);
|
||||
}
|
||||
|
||||
if((x($_SESSION, 'authenticated')) || (x($_POST, 'auth-params')) || (\App::$module === 'login'))
|
||||
if(!empty($_SESSION['authenticated']) || !empty($_POST['auth-params']) || App::$module === 'login') {
|
||||
require('include/auth.php');
|
||||
}
|
||||
|
||||
if (!$installed) {
|
||||
/* Allow an exception for the view module so that pcss will be interpreted during installation */
|
||||
if(\App::$module != 'view')
|
||||
\App::$module = 'setup';
|
||||
if(App::$module != 'view') {
|
||||
App::$module = 'setup';
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -111,17 +117,7 @@ class WebServer {
|
||||
|
||||
$Router->Dispatch();
|
||||
|
||||
// TODO: this is not used for anything atm and messes up comanche templates by adding some javascript
|
||||
//$this->set_homebase();
|
||||
|
||||
// now that we've been through the module content, see if the page reported
|
||||
// a permission problem and if so, a 403 response would seem to be in order.
|
||||
|
||||
if(isset($_SESSION['sysmsg']) && is_array($_SESSION['sysmsg']) && stristr(implode("", $_SESSION['sysmsg']), t('Permission denied'))) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 403 ' . t('Permission denied.'));
|
||||
}
|
||||
|
||||
call_hooks('page_end', \App::$page['content']);
|
||||
call_hooks('page_end', App::$page['content']);
|
||||
|
||||
construct_page();
|
||||
|
||||
@@ -129,14 +125,49 @@ class WebServer {
|
||||
}
|
||||
|
||||
|
||||
public function createRequest()
|
||||
{
|
||||
$input = null;
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$input = file_get_contents('php://input');
|
||||
}
|
||||
|
||||
$headers = [];
|
||||
|
||||
if (isset($_SERVER['CONTENT_TYPE'])) {
|
||||
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
|
||||
}
|
||||
|
||||
if (isset($_SERVER['CONTENT_LENGTH'])) {
|
||||
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
|
||||
}
|
||||
|
||||
foreach ($_SERVER as $k => $v) {
|
||||
if (str_starts_with($k, 'HTTP_')) {
|
||||
$field = str_replace('_', '-', strtolower(substr($k, 5)));
|
||||
$headers[$field] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
App::$request = new Request(
|
||||
$_SERVER['REQUEST_METHOD'],
|
||||
z_root() . ((App::$originalRequest) ?? $_SERVER['REQUEST_URI']),
|
||||
$headers,
|
||||
$input
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private function initialise_content() {
|
||||
|
||||
/* initialise content region */
|
||||
|
||||
if(! x(\App::$page, 'content'))
|
||||
\App::$page['content'] = '';
|
||||
if(empty(App::$page['content'])) {
|
||||
App::$page['content'] = '';
|
||||
}
|
||||
|
||||
call_hooks('page_content_top', \App::$page['content']);
|
||||
call_hooks('page_content_top', App::$page['content']);
|
||||
|
||||
}
|
||||
|
||||
@@ -148,44 +179,24 @@ class WebServer {
|
||||
* to all protocol drivers; thus doing it here avoids duplication.
|
||||
*/
|
||||
|
||||
if (( \App::$module === 'channel' ) && argc() > 1) {
|
||||
\App::$channel_links = [
|
||||
if (App::$module === 'channel' && argc() > 1) {
|
||||
App::$channel_links = [
|
||||
[
|
||||
'rel' => 'lrdd',
|
||||
'type' => 'application/xrd+xml',
|
||||
'url' => z_root() . '/xrd?f=&uri=acct%3A' . argv(1) . '%40' . \App::get_hostname()
|
||||
'url' => z_root() . '/xrd?f=&uri=acct%3A' . argv(1) . '%40' . App::get_hostname()
|
||||
],
|
||||
[
|
||||
'rel' => 'jrd',
|
||||
'type' => 'application/jrd+json',
|
||||
'url' => z_root() . '/.well-known/webfinger?f=&resource=acct%3A' . argv(1) . '%40' . \App::get_hostname()
|
||||
'url' => z_root() . '/.well-known/webfinger?f=&resource=acct%3A' . argv(1) . '%40' . App::get_hostname()
|
||||
],
|
||||
];
|
||||
$x = [ 'channel_address' => argv(1), 'channel_links' => \App::$channel_links ];
|
||||
$x = [ 'channel_address' => argv(1), 'channel_links' => App::$channel_links ];
|
||||
call_hooks('channel_links', $x );
|
||||
\App::$channel_links = $x['channel_links'];
|
||||
App::$channel_links = $x['channel_links'];
|
||||
header('Link: ' . \App::get_channel_links());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function set_homebase() {
|
||||
|
||||
// If you're just visiting, let javascript take you home
|
||||
|
||||
if(x($_SESSION, 'visitor_home')) {
|
||||
$homebase = $_SESSION['visitor_home'];
|
||||
}
|
||||
elseif(local_channel()) {
|
||||
$homebase = z_root() . '/channel/' . \App::$channel['channel_address'];
|
||||
}
|
||||
|
||||
if(isset($homebase)) {
|
||||
\App::$page['content'] .= '<script>var homebase = "' . $homebase . '";</script>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class Activity_order {
|
||||
return '';
|
||||
|
||||
if(! feature_enabled(local_channel(),'order_tab')) {
|
||||
set_pconfig(local_channel(), 'mod_network', 'order', 0);
|
||||
set_pconfig(local_channel(), 'mod_network', 'order', 'created');
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -26,17 +26,17 @@ class Activity_order {
|
||||
|
||||
if(x($_GET, 'order')) {
|
||||
switch($_GET['order']){
|
||||
case 'post':
|
||||
case 'created':
|
||||
$postord_active = 'active';
|
||||
set_pconfig(local_channel(), 'mod_network', 'order', 1);
|
||||
set_pconfig(local_channel(), 'mod_network', 'order', 'created');
|
||||
break;
|
||||
case 'comment':
|
||||
case 'commented':
|
||||
$commentord_active = 'active';
|
||||
set_pconfig(local_channel(), 'mod_network', 'order', 0);
|
||||
set_pconfig(local_channel(), 'mod_network', 'order', 'commented');
|
||||
break;
|
||||
case 'unthreaded':
|
||||
$unthreaded_active = 'active';
|
||||
set_pconfig(local_channel(), 'mod_network', 'order', 2);
|
||||
set_pconfig(local_channel(), 'mod_network', 'order', 'unthreaded');
|
||||
break;
|
||||
default:
|
||||
$commentord_active = 'active';
|
||||
@@ -44,19 +44,19 @@ class Activity_order {
|
||||
}
|
||||
}
|
||||
else {
|
||||
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
|
||||
$order = get_pconfig(local_channel(), 'mod_network', 'order', 'created');
|
||||
switch($order) {
|
||||
case 0:
|
||||
case 'commented':
|
||||
$commentord_active = 'active';
|
||||
break;
|
||||
case 1:
|
||||
case 'created':
|
||||
$postord_active = 'active';
|
||||
break;
|
||||
case 2:
|
||||
case 'unthreaded':
|
||||
$unthreaded_active = 'active';
|
||||
break;
|
||||
default:
|
||||
$commentord_active = 'active';
|
||||
$postord_active = 'active';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,26 +90,26 @@ class Activity_order {
|
||||
|
||||
|
||||
// tabs
|
||||
$tabs = [];
|
||||
$tabs[] = [
|
||||
'label' => t('Posted Date'),
|
||||
'icon' => '',
|
||||
'url'=>z_root() . '/' . $cmd . '?order=created' . $filter,
|
||||
'sel'=> $postord_active,
|
||||
'title' => t('Order by last posted date'),
|
||||
];
|
||||
|
||||
$tabs[] = [
|
||||
'label' => t('Commented Date'),
|
||||
'icon' => '',
|
||||
'url'=>z_root() . '/' . $cmd . '?f=&order=comment' . $filter,
|
||||
'url'=>z_root() . '/' . $cmd . '?order=commented' . $filter,
|
||||
'sel'=> $commentord_active,
|
||||
'title' => t('Order by last commented date'),
|
||||
];
|
||||
$tabs[] = [
|
||||
'label' => t('Posted Date'),
|
||||
'icon' => '',
|
||||
'url'=>z_root() . '/' . $cmd . '?f=&order=post' . $filter,
|
||||
'sel'=> $postord_active,
|
||||
'title' => t('Order by last posted date'),
|
||||
];
|
||||
|
||||
$tabs[] = array(
|
||||
'label' => t('Date Unthreaded'),
|
||||
'icon' => '',
|
||||
'url' => z_root() . '/' . $cmd . '?f=&order=unthreaded' . $filter,
|
||||
'url' => z_root() . '/' . $cmd . '?order=unthreaded' . $filter,
|
||||
'sel' => $unthreaded_active,
|
||||
'title' => t('Order unthreaded by date'),
|
||||
);
|
||||
|
||||
@@ -59,6 +59,9 @@ class Album {
|
||||
//edit album name
|
||||
$album_edit = null;
|
||||
|
||||
$ph = photo_factory('');
|
||||
$phototypes = $ph->supportedTypes();
|
||||
|
||||
$photos = array();
|
||||
if($r) {
|
||||
$twist = 'rotright';
|
||||
|
||||
@@ -223,7 +223,7 @@ class Channel_activities {
|
||||
$i[] = [
|
||||
'url' => z_root() . '/manage/' . $rr['channel_id'],
|
||||
'title' => '',
|
||||
'summary' => '<div class="text-truncate lh-sm"><img src="' . $rr['xchan_photo_s'] . '" class="menu-img-2">' . '<strong>' . $rr['channel_name'] . '</strong><br><small class="opacity-75">' . $rr['xchan_addr'] . '</small></div>',
|
||||
'summary' => '<div class="text-truncate lh-sm"><img src="' . $rr['xchan_photo_s'] . '" class="menu-img-2">' . '<strong>' . $rr['channel_name'] . '</strong><br><small class="text-body-secondary">' . $rr['xchan_addr'] . '</small></div>',
|
||||
'footer' => $footer
|
||||
];
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ class Messages {
|
||||
intval(TERM_FILE)
|
||||
);
|
||||
|
||||
$file_tags = [];
|
||||
|
||||
if ($r) {
|
||||
foreach($r as $rr) {
|
||||
$file_tags[] = $rr['term'];
|
||||
@@ -42,14 +44,14 @@ class Messages {
|
||||
'$feature_file' => feature_enabled(local_channel(), 'filing'),
|
||||
'$file_tags' => $file_tags,
|
||||
'$strings' => [
|
||||
'messages_title' => t('Public and restricted messages'),
|
||||
'direct_messages_title' => t('Direct messages'),
|
||||
'starred_messages_title' => t('Starred messages'),
|
||||
'messages_title' => t('Public and restricted conversations'),
|
||||
'direct_messages_title' => t('Private conversations'),
|
||||
'starred_messages_title' => t('Starred conversations'),
|
||||
'filed_messages_title' => t('Filed messages'),
|
||||
'notice_messages_title' => t('Notices'),
|
||||
'notice_messages_title' => t('Notifications'),
|
||||
'loading' => t('Loading'),
|
||||
'empty' => t('No messages'),
|
||||
'unseen_count' => t('Unseen'),
|
||||
'empty' => t('No conversations'),
|
||||
'unseen_count' => t('Unseen reactions'),
|
||||
'filter' => t('Filter by name or address'),
|
||||
'file_filter' => t('Filter by file name')
|
||||
]
|
||||
@@ -84,8 +86,6 @@ class Messages {
|
||||
$entries = [];
|
||||
$limit = 30;
|
||||
$order_sql = 'i.created DESC';
|
||||
$dummy_order_sql = '';
|
||||
$filter_sql = '';
|
||||
$loadtime = (($offset) ? $_SESSION['messages_loadtime'] : datetime_convert());
|
||||
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify', -1);
|
||||
|
||||
@@ -101,14 +101,18 @@ class Messages {
|
||||
$vnotify_sql_i = " AND i.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
|
||||
$filter_sql = '';
|
||||
if($type !== 'filed' && $author) {
|
||||
$filter_sql = " AND (i.owner_xchan = '" . protect_sprintf(dbesc($author)) . "') ";
|
||||
}
|
||||
|
||||
$filed_filter_sql = '';
|
||||
if($type === 'filed' && $file) {
|
||||
$filed_filter_sql = " AND (term.term = '" . protect_sprintf(dbesc($file)) . "') ";
|
||||
}
|
||||
|
||||
$dummy_order_sql = '';
|
||||
|
||||
switch($type) {
|
||||
case 'direct':
|
||||
$type_sql = ' AND i.item_private = 2 AND i.item_thread_top = 1 ';
|
||||
|
||||
@@ -21,16 +21,16 @@ class Notifications {
|
||||
'icon' => 'grid-3x3',
|
||||
'severity' => 'secondary',
|
||||
'label' => t('Network'),
|
||||
'title' => t('New network activity notifications'),
|
||||
'title' => t('Unseen network activity'),
|
||||
'viewall' => [
|
||||
'url' => 'network',
|
||||
'label' => t('Network stream')
|
||||
],
|
||||
'markall' => [
|
||||
'label' => t('Mark all notifications read')
|
||||
'label' => t('Mark all read')
|
||||
],
|
||||
'filter' => [
|
||||
'posts_label' => t('Show new posts only'),
|
||||
'posts_label' => t('Conversation starters'),
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
];
|
||||
@@ -40,17 +40,17 @@ class Notifications {
|
||||
'type' => 'home',
|
||||
'icon' => 'house',
|
||||
'severity' => 'danger',
|
||||
'label' => t('Home'),
|
||||
'title' => t('New home activity notifications'),
|
||||
'label' => t('Channel'),
|
||||
'title' => t('Unseen channel activity'),
|
||||
'viewall' => [
|
||||
'url' => 'channel/' . $channel['channel_address'],
|
||||
'label' => t('Home stream')
|
||||
'label' => t('Channel stream')
|
||||
],
|
||||
'markall' => [
|
||||
'label' => t('Mark all notifications seen')
|
||||
'label' => t('Mark all seen')
|
||||
],
|
||||
'filter' => [
|
||||
'posts_label' => t('Show new posts only'),
|
||||
'posts_label' => t('Conversation starters'),
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
];
|
||||
@@ -59,17 +59,17 @@ class Notifications {
|
||||
'type' => 'dm',
|
||||
'icon' => 'envelope',
|
||||
'severity' => 'danger',
|
||||
'label' => t('Direct Messages'),
|
||||
'title' => t('New direct messages notifications'),
|
||||
'label' => t('Private'),
|
||||
'title' => t('Unseen private activity'),
|
||||
'viewall' => [
|
||||
'url' => 'network/?dm=1',
|
||||
'label' => t('Direct messages stream')
|
||||
'label' => t('Private stream')
|
||||
],
|
||||
'markall' => [
|
||||
'label' => t('Mark all notifications read')
|
||||
'label' => t('Mark all read')
|
||||
],
|
||||
'filter' => [
|
||||
'posts_label' => t('Show new posts only'),
|
||||
'posts_label' => t('Conversation starters'),
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
];
|
||||
@@ -79,13 +79,13 @@ class Notifications {
|
||||
'icon' => 'calendar-date',
|
||||
'severity' => 'secondary',
|
||||
'label' => t('Events'),
|
||||
'title' => t('New events notifications'),
|
||||
'title' => t('Unseen events activity'),
|
||||
'viewall' => [
|
||||
'url' => 'cdav/calendar',
|
||||
'label' => t('View events')
|
||||
],
|
||||
'markall' => [
|
||||
'label' => t('Mark all events seen')
|
||||
'label' => t('Mark all seen')
|
||||
]
|
||||
];
|
||||
|
||||
@@ -94,10 +94,10 @@ class Notifications {
|
||||
'icon' => 'people',
|
||||
'severity' => 'danger',
|
||||
'label' => t('New Connections'),
|
||||
'title' => t('New connections notifications'),
|
||||
'title' => t('New connections'),
|
||||
'viewall' => [
|
||||
'url' => 'connections',
|
||||
'label' => t('View all connections')
|
||||
'label' => t('View all')
|
||||
]
|
||||
];
|
||||
|
||||
@@ -106,21 +106,21 @@ class Notifications {
|
||||
'icon' => 'folder',
|
||||
'severity' => 'danger',
|
||||
'label' => t('Files'),
|
||||
'title' => t('New files notifications'),
|
||||
'title' => t('Useen files activity'),
|
||||
];
|
||||
|
||||
$notifications[] = [
|
||||
'type' => 'notify',
|
||||
'icon' => 'exclamation-circle',
|
||||
'severity' => 'danger',
|
||||
'label' => t('Notices'),
|
||||
'title' => t('Notices'),
|
||||
'label' => t('Notifications'),
|
||||
'title' => t('Unseen notifications'),
|
||||
'viewall' => [
|
||||
'url' => 'notifications/system',
|
||||
'label' => t('View all notices')
|
||||
'label' => t('View all')
|
||||
],
|
||||
'markall' => [
|
||||
'label' => t('Mark all notices seen')
|
||||
'label' => t('Mark all seen')
|
||||
]
|
||||
];
|
||||
|
||||
@@ -129,7 +129,7 @@ class Notifications {
|
||||
'icon' => 'chat-quote',
|
||||
'severity' => 'secondary',
|
||||
'label' => t('Forums'),
|
||||
'title' => t('Forums'),
|
||||
'title' => t('Unseen forums activity'),
|
||||
'filter' => [
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
@@ -142,7 +142,7 @@ class Notifications {
|
||||
'icon' => 'person-exclamation',
|
||||
'severity' => 'danger',
|
||||
'label' => t('Registrations'),
|
||||
'title' => t('New registrations notifications'),
|
||||
'title' => t('Unseen registration activity'),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ class Notifications {
|
||||
'icon' => 'globe',
|
||||
'severity' => 'secondary',
|
||||
'label' => t('Public Stream'),
|
||||
'title' => t('New public stream notifications'),
|
||||
'title' => t('Unseen public stream activity'),
|
||||
'viewall' => [
|
||||
'url' => 'pubstream',
|
||||
'label' => t('Public stream')
|
||||
@@ -163,7 +163,7 @@ class Notifications {
|
||||
],
|
||||
*/
|
||||
'filter' => [
|
||||
'posts_label' => t('Show new posts only'),
|
||||
'posts_label' => t('Conversation starters'),
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
];
|
||||
|
||||
@@ -67,19 +67,19 @@ class Pinned {
|
||||
$attend = null;
|
||||
$canvote = false;
|
||||
|
||||
$conv_responses = [];
|
||||
$response_verbs[] = 'like';
|
||||
|
||||
if(in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
|
||||
$conv_responses['attendyes'] = [ 'title' => t('Attending','title') ];
|
||||
$conv_responses['attendno'] = [ 'title' => t('Not attending','title') ];
|
||||
$conv_responses['attendmaybe'] = [ 'title' => t('Might attend','title') ];
|
||||
if($commentable && $observer) {
|
||||
$attend = [ t('I will attend'), t('I will not attend'), t('I might attend') ];
|
||||
$isevent = true;
|
||||
}
|
||||
if(feature_enabled(\App::$profile['profile_uid'],'dislike')) {
|
||||
$response_verbs[] = 'dislike';
|
||||
}
|
||||
|
||||
$this->activity($item, $conv_responses);
|
||||
$response_verbs[] = 'announce';
|
||||
|
||||
if ($item['obj_type'] === 'Question') {
|
||||
$response_verbs[] = 'answer';
|
||||
}
|
||||
|
||||
$responses = get_responses($response_verbs, $item);
|
||||
|
||||
$verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
|
||||
$forged = ((! intval($item['item_verified']) && $item['sig']) ? t('Message signature incorrect') : '');
|
||||
@@ -110,6 +110,9 @@ class Pinned {
|
||||
'text' => strip_tags($body['html']),
|
||||
'id' => $item['id'],
|
||||
'mids' => json_encode([ $midb64 ]),
|
||||
'mid' => $item['uuid'],
|
||||
'rawmid' => $item['mid'],
|
||||
'parent' => $item['parent'],
|
||||
'isevent' => $isevent,
|
||||
'attend' => $attend,
|
||||
'conlabels' => [],
|
||||
@@ -151,7 +154,7 @@ class Pinned {
|
||||
'hide' => (! $is_new && isset($observer['xchan_hash']) && $observer['xchan_hash'] != $owner['xchan_hash'] ? t("Don't show") : ''),
|
||||
// end toolbar buttons
|
||||
'modal_dismiss' => t('Close'),
|
||||
'responses' => $conv_responses,
|
||||
'responses' => $responses,
|
||||
'author_id' => (($author['xchan_addr']) ? $author['xchan_addr'] : $author['xchan_url'])
|
||||
|
||||
];
|
||||
@@ -193,74 +196,14 @@ class Pinned {
|
||||
if(empty($mids_list))
|
||||
return [];
|
||||
|
||||
$r = q("SELECT * FROM item WHERE uuid IN ( '%s' ) AND uid = %d AND id = parent AND item_private = 0 ORDER BY created DESC",
|
||||
|
||||
$r = q("SELECT parent AS item_id FROM item WHERE uuid IN ( '%s' ) AND uid = %d AND id = parent AND item_private = 0",
|
||||
dbesc(implode(",", $mids_list)),
|
||||
intval($this->uid)
|
||||
);
|
||||
if($r)
|
||||
return $r;
|
||||
|
||||
return [];
|
||||
return items_by_parent_ids($r, blog_mode: true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief List activities on item
|
||||
*
|
||||
* @param array $item
|
||||
* @param array $conv_responses
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
private function activity($item, &$conv_responses) {
|
||||
|
||||
foreach(array_keys($conv_responses) as $verb) {
|
||||
$verb_sql = '';
|
||||
|
||||
switch($verb) {
|
||||
case 'like':
|
||||
$verb_sql = " AND verb IN ('Like', '" . ACTIVITY_LIKE . "') ";
|
||||
break;
|
||||
case 'dislike':
|
||||
$verb_sql = " AND verb IN ('Dislike', '" . ACTIVITY_DISLIKE . "') ";
|
||||
break;
|
||||
case 'attendyes':
|
||||
$verb_sql = " AND verb IN ('Accept', '" . ACTIVITY_ATTEND . "') ";
|
||||
break;
|
||||
case 'attendno':
|
||||
$verb_sql = " AND verb IN ('Reject', '" . ACTIVITY_ATTENDNO . "') ";
|
||||
break;
|
||||
case 'attendmaybe':
|
||||
$verb_sql = " AND verb IN ('TentativeAccept', '" . ACTIVITY_ATTENDMAYBE . "') ";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$r = q("SELECT * FROM item WHERE parent = %d AND id <> parent $verb_sql AND item_deleted = 0",
|
||||
intval($item['id'])
|
||||
);
|
||||
if(! $r) {
|
||||
unset($conv_responses[$verb]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$conv_responses[$verb]['count'] = count($r);
|
||||
$conv_responses[$verb]['button'] = get_response_button_text($verb, $conv_responses[$verb]['count']);
|
||||
|
||||
foreach($r as $rr) {
|
||||
|
||||
$author = q("SELECT * FROM xchan WHERE xchan_hash = '%s' LIMIT 1",
|
||||
dbesc($rr['author_xchan'])
|
||||
);
|
||||
$name = (($author && $author[0]['xchan_name']) ? $author[0]['xchan_name'] : t('Unknown'));
|
||||
$conv_responses[$verb]['list'][] = (($rr['author_xchan'] && $author && $author[0]['xchan_photo_s']) ?
|
||||
'<a class="dropdown-item" href="' . chanlink_hash($rr['author_xchan']) . '">' . '<img class="menu-img-1" src="' . zid($author[0]['xchan_photo_s']) . '" alt="' . urlencode($name) . '" /> ' . $name . '</a>' :
|
||||
'<a class="dropdown-item" href="#" class="disabled">' . $name . '</a>'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$conv_responses['count'] = count($conv_responses);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,10 @@ class Portfolio {
|
||||
//edit album name
|
||||
$album_edit = null;
|
||||
|
||||
|
||||
$ph = photo_factory('');
|
||||
$phototypes = $ph->supportedTypes();
|
||||
|
||||
$photos = array();
|
||||
if($r) {
|
||||
$twist = 'rotright';
|
||||
|
||||
@@ -12,7 +12,7 @@ class Zot6Handler implements IHandler {
|
||||
}
|
||||
|
||||
function Rekey($sender, $data, $hub) {
|
||||
return self::reply_rekey_request($sender, $data, $hub);
|
||||
return self::rekey_request($sender, $data, $hub);
|
||||
}
|
||||
|
||||
function Refresh($sender, $recipients, $hub, $force) {
|
||||
@@ -34,11 +34,13 @@ class Zot6Handler implements IHandler {
|
||||
|
||||
logger('notify received from ' . $hub['hubloc_url']);
|
||||
|
||||
$x = Libzot::fetch($data, $hub);
|
||||
$ret['delivery_report'] = $x;
|
||||
$x = Libzot::fetch($data);
|
||||
|
||||
if ($x) {
|
||||
$ret['delivery_report'] = $x;
|
||||
$ret['success'] = true;
|
||||
}
|
||||
|
||||
$ret['success'] = true;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
425
boot.php
425
boot.php
@@ -36,6 +36,9 @@ use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\DB_Upgrade;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Render\SmartyTemplate;
|
||||
use Zotlabs\Render\Theme;
|
||||
use Zotlabs\Web\HttpMeta;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
|
||||
@@ -46,6 +49,7 @@ require_once('include/text.php');
|
||||
require_once('include/datetime.php');
|
||||
require_once('include/language.php');
|
||||
require_once('include/nav.php');
|
||||
require_once('include/observer.php');
|
||||
require_once('include/permissions.php');
|
||||
require_once('include/features.php');
|
||||
require_once('include/taxonomy.php');
|
||||
@@ -66,7 +70,7 @@ require_once('include/security.php');
|
||||
|
||||
|
||||
define('PLATFORM_NAME', 'hubzilla');
|
||||
define('STD_VERSION', '10.0.3');
|
||||
define('STD_VERSION', '10.4');
|
||||
define('ZOT_REVISION', '6.0');
|
||||
|
||||
define('DB_UPDATE_VERSION', 1263);
|
||||
@@ -133,6 +137,12 @@ define('PNG_QUALITY', 8);
|
||||
*/
|
||||
define('WEBP_QUALITY', 80);
|
||||
|
||||
/**
|
||||
* App::$config['system']['avif_quality'] from 1 (maximum compressed) to 100 (uncompressed)
|
||||
*/
|
||||
define('AVIF_QUALITY', 80);
|
||||
|
||||
|
||||
/**
|
||||
* Language detection parameters
|
||||
*/
|
||||
@@ -175,6 +185,13 @@ if (!defined('STORAGE_DEFAULT_PERMISSIONS')) {
|
||||
*/
|
||||
define('MAX_IMAGE_LENGTH', -1);
|
||||
|
||||
/**
|
||||
* Those are the current limits we can store in the DB
|
||||
*/
|
||||
|
||||
define('MAX_FILENAME_LENGTH', 191);
|
||||
define('MAX_FOLDER_LENGTH', 64);
|
||||
|
||||
|
||||
/**
|
||||
* log levels
|
||||
@@ -640,8 +657,10 @@ function sys_boot(): bool {
|
||||
// allow somebody to set some initial settings just in case they can't
|
||||
// install without special fiddling
|
||||
|
||||
if (App::$install && file_exists('.htpreconfig.php'))
|
||||
if (App::$install && file_exists('.htpreconfig.php')) {
|
||||
// @phpstan-ignore include.fileNotFound
|
||||
@include('.htpreconfig.php');
|
||||
}
|
||||
|
||||
if (array_key_exists('default_timezone', get_defined_vars())) {
|
||||
App::$config['system']['timezone'] = $default_timezone;
|
||||
@@ -654,7 +673,6 @@ function sys_boot(): bool {
|
||||
App::$timezone = ((App::$config['system']['timezone']) ? App::$config['system']['timezone'] : 'UTC');
|
||||
date_default_timezone_set(App::$timezone);
|
||||
|
||||
|
||||
if (!defined('DEFAULT_PLATFORM_ICON')) {
|
||||
define('DEFAULT_PLATFORM_ICON', '/images/hz-32.png');
|
||||
}
|
||||
@@ -756,7 +774,8 @@ class miniApp {
|
||||
*
|
||||
*/
|
||||
class App {
|
||||
|
||||
public static $request = null; // psr7 request
|
||||
public static $originalRequest = null; // not used currently, will be needed when we start signing messages with RFC 9421
|
||||
public static $install = false; // true if we are installing the software
|
||||
public static $account = null; // account record of the logged-in account
|
||||
public static $channel = null; // channel record of the current channel of the logged-in account
|
||||
@@ -854,6 +873,9 @@ class App {
|
||||
*/
|
||||
public static $template_engine_instance = [];
|
||||
|
||||
/// Page layouts for comanche
|
||||
public static array $page_layouts = [];
|
||||
|
||||
private static $ldelim = [
|
||||
'internal' => '',
|
||||
'smarty3' => '{{'
|
||||
@@ -896,46 +918,43 @@ class App {
|
||||
set_include_path(
|
||||
'include' . PATH_SEPARATOR
|
||||
. 'library' . PATH_SEPARATOR
|
||||
. 'library/langdet' . PATH_SEPARATOR
|
||||
. '.');
|
||||
|
||||
self::$scheme = 'http';
|
||||
if (x($_SERVER, 'HTTPS') && $_SERVER['HTTPS'])
|
||||
self::$scheme = 'https';
|
||||
elseif (x($_SERVER, 'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443))
|
||||
self::$scheme = 'https';
|
||||
|
||||
if (x($_SERVER, 'SERVER_NAME')) {
|
||||
if (!empty($_SERVER['HTTPS'])) {
|
||||
self::$scheme = 'https';
|
||||
}
|
||||
elseif (!empty($_SERVER['SERVER_PORT']) && intval($_SERVER['SERVER_PORT']) == 443) {
|
||||
self::$scheme = 'https';
|
||||
}
|
||||
|
||||
if (!empty($_SERVER['SERVER_NAME'])) {
|
||||
self::$hostname = punify($_SERVER['SERVER_NAME']);
|
||||
|
||||
if (x($_SERVER, 'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443)
|
||||
if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
|
||||
self::$hostname .= ':' . $_SERVER['SERVER_PORT'];
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out if we are running at the top of a domain
|
||||
* or in a sub-directory and adjust accordingly
|
||||
*/
|
||||
$path = trim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
|
||||
if (isset($path) && strlen($path) && ($path != self::$path))
|
||||
|
||||
if (isset($path) && strlen($path) && ($path != self::$path)) {
|
||||
self::$path = $path;
|
||||
}
|
||||
}
|
||||
|
||||
if ((x($_SERVER, 'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'], 0, 2) === "q=") {
|
||||
self::$query_string = str_replace(['<', '>'], ['<', '>'], substr($_SERVER['QUERY_STRING'], 2));
|
||||
|
||||
// removing trailing / - maybe a nginx problem
|
||||
if (substr(self::$query_string, 0, 1) == "/")
|
||||
self::$query_string = substr(self::$query_string, 1);
|
||||
|
||||
// trim trailing '&' if no extra args are present
|
||||
self::$query_string = rtrim(self::$query_string, '&');
|
||||
|
||||
// change the first & to ?
|
||||
self::$query_string = preg_replace('/&/', '?', self::$query_string, 1);
|
||||
if (!empty($_SERVER['REQUEST_URI'])) {
|
||||
self::$query_string = str_replace(['<', '>'], ['<', '>'], $_SERVER['REQUEST_URI']);
|
||||
self::$query_string = ltrim(self::$query_string, '/');
|
||||
}
|
||||
|
||||
if (x($_GET, 'q'))
|
||||
if (!empty($_GET['q'])) {
|
||||
self::$cmd = escape_tags(trim($_GET['q'], '/\\'));
|
||||
}
|
||||
|
||||
// Serve raw files from the file system in certain cases.
|
||||
$filext = pathinfo(self::$cmd, PATHINFO_EXTENSION);
|
||||
@@ -985,8 +1004,9 @@ class App {
|
||||
|
||||
// unix style "homedir"
|
||||
|
||||
if ((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@'))
|
||||
if (substr(self::$cmd, 0, 1) === '~' || substr(self::$cmd, 0, 1) === '@') {
|
||||
self::$cmd = 'channel/' . substr(self::$cmd, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Break the URL path into C style argc/argv style arguments for our
|
||||
@@ -1006,7 +1026,7 @@ class App {
|
||||
self::$argv = explode('/', self::$cmd);
|
||||
|
||||
self::$argc = count(self::$argv);
|
||||
if ((array_key_exists('0', self::$argv)) && strlen(self::$argv[0])) {
|
||||
if (array_key_exists('0', self::$argv) && strlen(self::$argv[0])) {
|
||||
if (strpos(self::$argv[0], '.')) {
|
||||
$_REQUEST['module_format'] = substr(self::$argv[0], strpos(self::$argv[0], '.') + 1);
|
||||
self::$argv[0] = substr(self::$argv[0], 0, strpos(self::$argv[0], '.'));
|
||||
@@ -1014,8 +1034,9 @@ class App {
|
||||
|
||||
self::$module = str_replace(".", "_", self::$argv[0]);
|
||||
self::$module = str_replace("-", "_", self::$module);
|
||||
if (strpos(self::$module, '_') === 0)
|
||||
if (strpos(self::$module, '_') === 0) {
|
||||
self::$module = substr(self::$module, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
self::$argc = 1;
|
||||
@@ -1029,22 +1050,26 @@ class App {
|
||||
* pagination
|
||||
*/
|
||||
|
||||
self::$pager['page'] = ((x($_GET, 'page') && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1);
|
||||
self::$pager['page'] = ((!empty($_GET['page']) && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1);
|
||||
self::$pager['itemspage'] = 60;
|
||||
self::$pager['start'] = (self::$pager['page'] * self::$pager['itemspage']) - self::$pager['itemspage'];
|
||||
if (self::$pager['start'] < 0)
|
||||
|
||||
if (self::$pager['start'] < 0) {
|
||||
self::$pager['start'] = 0;
|
||||
}
|
||||
|
||||
self::$pager['total'] = 0;
|
||||
|
||||
/*
|
||||
* register template engines
|
||||
*/
|
||||
|
||||
self::$meta = new Zotlabs\Web\HttpMeta();
|
||||
self::$meta = new HttpMeta();
|
||||
|
||||
// create an instance of the smarty template engine so we can register it.
|
||||
|
||||
$smarty = new Zotlabs\Render\SmartyTemplate();
|
||||
$smarty = new SmartyTemplate();
|
||||
|
||||
/// @todo validate if this is still the desired behavior
|
||||
self::register_template_engine(get_class($smarty));
|
||||
|
||||
@@ -1089,10 +1114,12 @@ class App {
|
||||
self::$scheme = $parsed['scheme'];
|
||||
|
||||
self::$hostname = punify($parsed['host']);
|
||||
if (x($parsed, 'port'))
|
||||
if (!empty($parsed['port'])) {
|
||||
self::$hostname .= ':' . $parsed['port'];
|
||||
if (x($parsed, 'path'))
|
||||
}
|
||||
if (!empty($parsed['path'])) {
|
||||
self::$path = trim($parsed['path'], '\\/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1197,28 +1224,22 @@ class App {
|
||||
|
||||
public static function build_pagehead() {
|
||||
|
||||
$user_scalable = ((local_channel()) ? get_pconfig(local_channel(), 'system', 'user_scalable') : 0);
|
||||
if ($user_scalable === false)
|
||||
$user_scalable = 0;
|
||||
|
||||
$preload_images = ((local_channel()) ? get_pconfig(local_channel(), 'system', 'preload_images') : 0);
|
||||
if ($preload_images === false)
|
||||
$preload_images = 0;
|
||||
$user_scalable = ((local_channel()) ? get_pconfig(local_channel(), 'system', 'user_scalable', 0) : 0);
|
||||
|
||||
$interval = ((local_channel()) ? get_pconfig(local_channel(), 'system', 'update_interval') : 80000);
|
||||
if ($interval < 10000)
|
||||
if ($interval < 10000) {
|
||||
$interval = 80000;
|
||||
|
||||
$theme_color = ((local_channel()) ? get_pconfig(local_channel(), 'redbasic', 'nav_bg') : App::$theme_info['theme_color']);
|
||||
if (!$theme_color) {
|
||||
$theme_color = App::$theme_info['theme_color'];
|
||||
}
|
||||
|
||||
if (!isset(self::$page['title']) && isset(self::$config['system']['sitename']))
|
||||
self::$page['title'] = self::$config['system']['sitename'];
|
||||
$theme_color = ((local_channel()) ? get_pconfig(local_channel(), 'redbasic', 'nav_bg', App::$theme_info['theme_color']) : App::$theme_info['theme_color']);
|
||||
|
||||
if (isset(self::$page['title']))
|
||||
if (empty(self::$page['title']) && !empty(self::$config['system']['sitename'])) {
|
||||
self::$page['title'] = self::$config['system']['sitename'];
|
||||
}
|
||||
|
||||
if (!empty(self::$page['title'])) {
|
||||
$pagemeta = ['og:title' => self::$page['title']];
|
||||
}
|
||||
|
||||
call_hooks('page_meta', $pagemeta);
|
||||
|
||||
@@ -1236,7 +1257,7 @@ class App {
|
||||
self::$meta->set('generator', Zotlabs\Lib\System::get_platform_name());
|
||||
self::$meta->set('theme-color', $theme_color);
|
||||
|
||||
head_add_link(['rel' => 'shortcut icon', 'href' => head_get_icon()]);
|
||||
head_add_link(['rel' => 'shortcut icon', 'href' => static::head_get_icon()]);
|
||||
head_add_link(['rel' => 'apple-touch-icon', 'href' => '/images/app/hz-192.png']);
|
||||
|
||||
|
||||
@@ -1255,7 +1276,6 @@ class App {
|
||||
|
||||
self::$page['htmlhead'] = replace_macros(get_markup_template('head.tpl'),
|
||||
[
|
||||
'$preload_images' => $preload_images,
|
||||
'$user_scalable' => $user_scalable,
|
||||
'$query' => urlencode(self::$query_string),
|
||||
'$baseurl' => self::get_baseurl(),
|
||||
@@ -1270,7 +1290,7 @@ class App {
|
||||
'$js_strings' => js_strings(),
|
||||
'$zid' => get_my_address(),
|
||||
'$channel_id' => self::$profile['uid'] ?? 0,
|
||||
'$auto_save_draft' => ((isset(self::$profile['uid']) && feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false"),
|
||||
'$auto_save_draft' => ((isset(self::$profile_uid) && feature_enabled(self::$profile_uid, 'auto_save_draft')) ? "true" : "false"),
|
||||
'$module' => App::$module,
|
||||
'$lang' => App::$language
|
||||
]
|
||||
@@ -1291,7 +1311,7 @@ class App {
|
||||
public static function register_template_engine($class, $name = '') {
|
||||
if (!$name) {
|
||||
$v = get_class_vars($class);
|
||||
if (x($v, "name")) {
|
||||
if (!empty($v['name'])) {
|
||||
$name = $v['name'];
|
||||
}
|
||||
}
|
||||
@@ -1317,7 +1337,7 @@ class App {
|
||||
}
|
||||
else {
|
||||
$template_engine = 'smarty3';
|
||||
if (x(self::$theme, 'template_engine')) {
|
||||
if (!empty(self::$theme['template_engine'])) {
|
||||
$template_engine = self::$theme['template_engine'];
|
||||
}
|
||||
}
|
||||
@@ -1359,15 +1379,29 @@ class App {
|
||||
return self::$rdelim[$engine];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shortcut icon to be used for the current page.
|
||||
*
|
||||
* @param string $icon A URL to the image to use for the
|
||||
* shortcut icon.
|
||||
*/
|
||||
public static function head_set_icon($icon) {
|
||||
self::$data['pageicon'] = $icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shortcut icon as an absolute URL.
|
||||
*
|
||||
* @return string The absolute URL of the current shortcur icon.
|
||||
*/
|
||||
public static function head_get_icon() {
|
||||
$icon = self::$data['pageicon'];
|
||||
if (!strpos($icon, '://'))
|
||||
$icon = z_root() . $icon;
|
||||
return $icon;
|
||||
|
||||
if (str_contains($icon, '://')) {
|
||||
return $icon;
|
||||
}
|
||||
|
||||
return z_root() . $icon;
|
||||
}
|
||||
|
||||
} // End App class
|
||||
@@ -1420,21 +1454,6 @@ function system_unavailable() {
|
||||
}
|
||||
|
||||
|
||||
function clean_urls() {
|
||||
|
||||
// if(App::$config['system']['clean_urls'])
|
||||
return true;
|
||||
// return false;
|
||||
}
|
||||
|
||||
function z_path() {
|
||||
$base = z_root();
|
||||
if (!clean_urls())
|
||||
$base .= '/?q=';
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the baseurl.
|
||||
*
|
||||
@@ -1446,19 +1465,6 @@ function z_root() {
|
||||
return App::get_baseurl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return absolute URL for given $path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function absurl($path) {
|
||||
if (strpos($path, '/') === 0)
|
||||
return z_path() . $path;
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
function os_mkdir($path, $mode = 0777, $recursive = false) {
|
||||
$oldumask = @umask(0);
|
||||
@@ -1511,10 +1517,11 @@ function is_ajax() {
|
||||
function check_config() {
|
||||
|
||||
$saved = Config::Get('system', 'urlverify');
|
||||
if (!$saved)
|
||||
if (!$saved) {
|
||||
Config::Set('system', 'urlverify', bin2hex(z_root()));
|
||||
}
|
||||
|
||||
if (($saved) && ($saved != bin2hex(z_root()))) {
|
||||
if ($saved && $saved !== bin2hex(z_root())) {
|
||||
// our URL changed. Do something.
|
||||
|
||||
$oldurl = hex2bin($saved);
|
||||
@@ -1526,12 +1533,13 @@ function check_config() {
|
||||
$is_ip_addr = ((preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $host)) ? true : false);
|
||||
$was_ip_addr = ((preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $oldhost)) ? true : false);
|
||||
// only change the url to an ip address if it was already an ip and not a dns name
|
||||
if ((!$is_ip_addr) || ($is_ip_addr && $was_ip_addr)) {
|
||||
if (!$is_ip_addr || ($is_ip_addr && $was_ip_addr)) {
|
||||
fix_system_urls($oldurl, z_root());
|
||||
Config::Set('system', 'urlverify', bin2hex(z_root()));
|
||||
}
|
||||
else
|
||||
else {
|
||||
logger('Attempt to change baseurl from a DNS name to an IP address was refused.');
|
||||
}
|
||||
}
|
||||
|
||||
// This will actually set the url to the one stored in .htconfig, and ignore what
|
||||
@@ -1778,7 +1786,6 @@ function login($register = false, $form_id = 'main_login', $hiddens = false, $lo
|
||||
* @brief Used to end the current process, after saving session state.
|
||||
*/
|
||||
function killme() {
|
||||
|
||||
register_shutdown_function('shutdown');
|
||||
exit;
|
||||
}
|
||||
@@ -1795,25 +1802,6 @@ function shutdown() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity id of locally logged in account or false.
|
||||
*
|
||||
* Returns numeric account_id if authenticated or 0. It is possible to be
|
||||
* authenticated and not connected to a channel.
|
||||
*
|
||||
* @return int|bool account_id or false
|
||||
*/
|
||||
function get_account_id() {
|
||||
|
||||
if (isset($_SESSION['account_id']))
|
||||
return intval($_SESSION['account_id']);
|
||||
|
||||
if (App::$account)
|
||||
return intval(App::$account['account_id']);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity id (channel_id) of locally logged in channel or false.
|
||||
*
|
||||
@@ -1828,8 +1816,9 @@ function get_account_id() {
|
||||
function local_channel() {
|
||||
if (session_id()
|
||||
&& array_key_exists('authenticated', $_SESSION) && $_SESSION['authenticated']
|
||||
&& array_key_exists('uid', $_SESSION) && intval($_SESSION['uid']))
|
||||
&& array_key_exists('uid', $_SESSION) && intval($_SESSION['uid'])) {
|
||||
return intval($_SESSION['uid']);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1849,8 +1838,9 @@ function local_channel() {
|
||||
function remote_channel() {
|
||||
if (session_id()
|
||||
&& array_key_exists('authenticated', $_SESSION) && $_SESSION['authenticated']
|
||||
&& array_key_exists('visitor_id', $_SESSION) && $_SESSION['visitor_id'])
|
||||
&& array_key_exists('visitor_id', $_SESSION) && $_SESSION['visitor_id']) {
|
||||
return $_SESSION['visitor_id'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1891,27 +1881,6 @@ function can_view_public_stream() {
|
||||
*/
|
||||
function notice($s) {
|
||||
|
||||
/*
|
||||
|
||||
if (!session_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['sysmsg'])) {
|
||||
$_SESSION['sysmsg'] = [];
|
||||
}
|
||||
|
||||
// ignore duplicated error messages which haven't yet been displayed
|
||||
|
||||
if (in_array($s, $_SESSION['sysmsg'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (App::$interactive) {
|
||||
$_SESSION['sysmsg'][] = $s;
|
||||
}
|
||||
*/
|
||||
|
||||
$hash = get_observer_hash();
|
||||
$sse_id = false;
|
||||
|
||||
@@ -1960,25 +1929,6 @@ function notice($s) {
|
||||
* @param string $s Text to display
|
||||
*/
|
||||
function info($s) {
|
||||
/*
|
||||
if (!session_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['sysmsg_info'])) {
|
||||
$_SESSION['sysmsg_info'] = [];
|
||||
}
|
||||
|
||||
// ignore duplicated error messages which haven't yet been displayed
|
||||
|
||||
if (in_array($s, $_SESSION['sysmsg_info'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (App::$interactive) {
|
||||
$_SESSION['sysmsg_info'][] = $s;
|
||||
}
|
||||
*/
|
||||
|
||||
$hash = get_observer_hash();
|
||||
$sse_id = false;
|
||||
@@ -2065,7 +2015,7 @@ function proc_run() {
|
||||
return;
|
||||
|
||||
if (count($args) && $args[0] === 'php') {
|
||||
$args[0] = ((x(App::$config, 'system')) && (x(App::$config['system'], 'php_path')) && (strlen(App::$config['system']['php_path'])) ? App::$config['system']['php_path'] : 'php');
|
||||
$args[0] = ((!empty(App::$config['system']['php_path'])) ? App::$config['system']['php_path'] : 'php');
|
||||
}
|
||||
|
||||
$args = array_map('escapeshellarg', $args);
|
||||
@@ -2077,10 +2027,12 @@ function proc_run() {
|
||||
proc_close(proc_open($cmd, [], $foo));
|
||||
}
|
||||
else {
|
||||
if (Config::Get('system', 'use_proc_open'))
|
||||
if (Config::Get('system', 'use_proc_open')) {
|
||||
proc_close(proc_open($cmdline . " &", [], $foo));
|
||||
else
|
||||
}
|
||||
else {
|
||||
exec($cmdline . ' > /dev/null &');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2105,15 +2057,17 @@ function is_windows() {
|
||||
* @return bool true if user is an admin
|
||||
*/
|
||||
function is_site_admin() {
|
||||
|
||||
if (!session_id())
|
||||
if (!session_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($_SESSION['delegate']))
|
||||
if (isset($_SESSION['delegate'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($_SESSION['authenticated']) && is_array(App::$account) && (App::$account['account_roles'] & ACCOUNT_ROLE_ADMIN))
|
||||
if (isset($_SESSION['authenticated']) && is_array(App::$account) && (App::$account['account_roles'] & ACCOUNT_ROLE_ADMIN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -2127,13 +2081,15 @@ function is_site_admin() {
|
||||
*/
|
||||
function is_developer() {
|
||||
|
||||
if (!session_id())
|
||||
if (!session_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((intval($_SESSION['authenticated']))
|
||||
&& (is_array(App::$account))
|
||||
&& (App::$account['account_roles'] & ACCOUNT_ROLE_DEVELOPER))
|
||||
if (intval($_SESSION['authenticated'])
|
||||
&& is_array(App::$account)
|
||||
&& (App::$account['account_roles'] & ACCOUNT_ROLE_DEVELOPER)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -2143,8 +2099,9 @@ function load_contact_links($uid) {
|
||||
|
||||
$ret = [];
|
||||
|
||||
if (!$uid || x(App::$contacts, 'empty'))
|
||||
if (!$uid || !empty(App::$contacts['empty'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// logger('load_contact_links');
|
||||
|
||||
@@ -2156,44 +2113,11 @@ function load_contact_links($uid) {
|
||||
$ret[$rv['xchan_hash']] = $rv;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
$ret['empty'] = true;
|
||||
|
||||
App::$contacts = $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns querystring as string from a mapped array.
|
||||
*
|
||||
* @param array $params mapped array with query parameters
|
||||
* @param string $name of parameter, default null
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function build_querystring($params, $name = null) {
|
||||
$ret = '';
|
||||
foreach ($params as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
if ($name === null) {
|
||||
$ret .= build_querystring($val, $key);
|
||||
}
|
||||
else {
|
||||
$ret .= build_querystring($val, $name . "[$key]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
$val = urlencode($val);
|
||||
if ($name != null) {
|
||||
$ret .= $name . "[$key]" . "=$val&";
|
||||
}
|
||||
else {
|
||||
$ret .= "$key=$val&";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
App::$contacts = $ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -2205,8 +2129,9 @@ function argc() {
|
||||
}
|
||||
|
||||
function argv($x) {
|
||||
if (array_key_exists($x, App::$argv))
|
||||
if (array_key_exists($x, App::$argv)) {
|
||||
return App::$argv[$x];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
@@ -2215,21 +2140,6 @@ function dba_timer() {
|
||||
return microtime(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns xchan_hash from the observer.
|
||||
*
|
||||
* Observer can be a local or remote channel.
|
||||
*
|
||||
* @return string xchan_hash from observer, otherwise empty string if no observer
|
||||
*/
|
||||
function get_observer_hash() {
|
||||
$observer = App::get_observer();
|
||||
if (is_array($observer))
|
||||
return $observer['xchan_hash'];
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the complete URL of the current page, e.g.: http(s)://something.com/network
|
||||
*
|
||||
@@ -2253,22 +2163,6 @@ function curPageURL() {
|
||||
return $pageURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a custom navigation by name???
|
||||
*
|
||||
* If no $navname provided load default page['nav']
|
||||
*
|
||||
* @param string $navname
|
||||
*
|
||||
* @return mixed
|
||||
* @todo not fully implemented yet
|
||||
*
|
||||
*/
|
||||
function get_custom_nav($navname) {
|
||||
if (!$navname)
|
||||
return App::$page['nav'];
|
||||
// load custom nav menu by name here
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads a page definition file for a module.
|
||||
@@ -2368,30 +2262,36 @@ function construct_page() {
|
||||
nav($navbar);
|
||||
}
|
||||
|
||||
$current_theme = Zotlabs\Render\Theme::current();
|
||||
$current_theme = Theme::current();
|
||||
// logger('current_theme: ' . print_r($current_theme,true));
|
||||
// Zotlabs\Render\Theme::debug();
|
||||
|
||||
if (($p = theme_include($current_theme[0] . '.js')) != '')
|
||||
if (($p = theme_include($current_theme[0] . '.js')) != '') {
|
||||
head_add_js('/' . $p);
|
||||
}
|
||||
|
||||
if (($p = theme_include('mod_' . App::$module . '.php')) != '')
|
||||
if (($p = theme_include('mod_' . App::$module . '.php')) != '') {
|
||||
require_once($p);
|
||||
}
|
||||
|
||||
require_once('include/js_strings.php');
|
||||
|
||||
if (x(App::$page, 'template_style'))
|
||||
if (!empty(App::$page['template_style'])) {
|
||||
head_add_css(App::$page['template_style'] . '.css');
|
||||
else
|
||||
head_add_css(((x(App::$page, 'template')) ? App::$page['template'] : 'default') . '.css');
|
||||
}
|
||||
else {
|
||||
head_add_css(((!empty(App::$page['template'])) ? App::$page['template'] : 'default') . '.css');
|
||||
}
|
||||
|
||||
if (($p = theme_include('mod_' . App::$module . '.css')) != '')
|
||||
if (($p = theme_include('mod_' . App::$module . '.css')) != '') {
|
||||
head_add_css('mod_' . App::$module . '.css');
|
||||
}
|
||||
|
||||
head_add_css(Zotlabs\Render\Theme::url());
|
||||
head_add_css(Theme::url());
|
||||
|
||||
if (($p = theme_include('mod_' . App::$module . '.js')) != '')
|
||||
if (($p = theme_include('mod_' . App::$module . '.js')) != '') {
|
||||
head_add_js('mod_' . App::$module . '.js');
|
||||
}
|
||||
|
||||
App::build_pagehead();
|
||||
|
||||
@@ -2423,7 +2323,6 @@ function construct_page() {
|
||||
call_hooks('construct_page', $arr);
|
||||
App::$layout = $arr['layout'];
|
||||
|
||||
|
||||
foreach (App::$layout as $k => $v) {
|
||||
if ((strpos($k, 'region_') === 0) && strlen($v)) {
|
||||
if (strpos($v, '$region_') !== false) {
|
||||
@@ -2458,8 +2357,9 @@ function construct_page() {
|
||||
|
||||
// security headers - see https://securityheaders.io
|
||||
|
||||
if (App::get_scheme() === 'https' && isset(App::$config['system']['transport_security_header']) && intval(App::$config['system']['transport_security_header']) == 1)
|
||||
if (App::get_scheme() === 'https' && isset(App::$config['system']['transport_security_header']) && intval(App::$config['system']['transport_security_header']) == 1) {
|
||||
header("Strict-Transport-Security: max-age=31536000");
|
||||
}
|
||||
|
||||
if (isset(App::$config['system']['content_security_policy']) && intval(App::$config['system']['content_security_policy']) == 1) {
|
||||
$cspsettings = [
|
||||
@@ -2511,7 +2411,7 @@ function construct_page() {
|
||||
}
|
||||
|
||||
require_once(theme_include(
|
||||
((x(App::$page, 'template')) ? App::$page['template'] : 'default') . '.php')
|
||||
((!empty(App::$page['template'])) ? App::$page['template'] : 'default') . '.php')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2530,23 +2430,7 @@ function appdirpath() {
|
||||
* @param string $icon
|
||||
*/
|
||||
function head_set_icon($icon) {
|
||||
|
||||
App::$data['pageicon'] = $icon;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the pageicon.
|
||||
*
|
||||
* @return string absolut path to pageicon
|
||||
*/
|
||||
function head_get_icon() {
|
||||
|
||||
$icon = App::$data['pageicon'];
|
||||
if (!strpos($icon, '://'))
|
||||
$icon = z_root() . $icon;
|
||||
|
||||
return $icon;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2555,8 +2439,9 @@ function head_get_icon() {
|
||||
* @return string
|
||||
*/
|
||||
function get_directory_realm() {
|
||||
if ($x = Config::Get('system', 'directory_realm'))
|
||||
if ($x = Config::Get('system', 'directory_realm')) {
|
||||
return $x;
|
||||
}
|
||||
|
||||
return DIRECTORY_REALM;
|
||||
}
|
||||
@@ -2574,8 +2459,9 @@ function get_directory_primary() {
|
||||
return z_root();
|
||||
}
|
||||
|
||||
if ($x = Config::Get('system', 'directory_primary'))
|
||||
if ($x = Config::Get('system', 'directory_primary')) {
|
||||
return $x;
|
||||
}
|
||||
|
||||
return DIRECTORY_FALLBACK_MASTER;
|
||||
}
|
||||
@@ -2594,18 +2480,22 @@ function get_poller_runtime() {
|
||||
|
||||
function z_get_upload_dir() {
|
||||
$upload_dir = Config::Get('system', 'uploaddir');
|
||||
if (!$upload_dir)
|
||||
if (!$upload_dir) {
|
||||
$upload_dir = ini_get('upload_tmp_dir');
|
||||
if (!$upload_dir)
|
||||
}
|
||||
|
||||
if (!$upload_dir) {
|
||||
$upload_dir = sys_get_temp_dir();
|
||||
}
|
||||
|
||||
return $upload_dir;
|
||||
}
|
||||
|
||||
function z_get_temp_dir() {
|
||||
$temp_dir = Config::Get('system', 'tempdir');
|
||||
if (!$temp_dir)
|
||||
if (!$temp_dir) {
|
||||
$temp_dir = sys_get_temp_dir();
|
||||
}
|
||||
|
||||
return $temp_dir;
|
||||
}
|
||||
@@ -2622,8 +2512,9 @@ function z_check_cert() {
|
||||
if (!$x['success']) {
|
||||
$recurse = 0;
|
||||
$y = z_fetch_url(z_root() . '/siteinfo.json', false, $recurse, ['novalidate' => true]);
|
||||
if ($y['success'])
|
||||
if ($y['success']) {
|
||||
cert_bad_email();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2656,8 +2547,9 @@ function check_for_new_perms() {
|
||||
|
||||
// Do not execute if we are in the middle of a git update and the relevant versions don't match
|
||||
|
||||
if (Permissions::version() != PermissionRoles::version())
|
||||
if (Permissions::version() != PermissionRoles::version()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pregistered = Config::Get('system', 'perms');
|
||||
|
||||
@@ -2720,8 +2612,9 @@ function check_for_new_perms() {
|
||||
}
|
||||
|
||||
// We should probably call perms_refresh here, but this should get pushed in 24 hours and there is no urgency
|
||||
if ($found_new_perm)
|
||||
if ($found_new_perm) {
|
||||
Config::Set('system', 'perms', $pcurrent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,23 +41,23 @@
|
||||
"simplepie/simplepie": "~1.5",
|
||||
"league/html-to-markdown": "^5.0",
|
||||
"pear/text_languagedetect": "^1.0",
|
||||
"commerceguys/intl": "~1.1.0",
|
||||
"commerceguys/intl": "^2.0.6",
|
||||
"lukasreschke/id3parser": "^0.0.3",
|
||||
"smarty/smarty": "^4.1",
|
||||
"smarty/smarty": "^5.4",
|
||||
"ramsey/uuid": "^4.1",
|
||||
"twbs/bootstrap": "^5.3",
|
||||
"blueimp/jquery-file-upload": "^10.3",
|
||||
"desandro/imagesloaded": "^4.1",
|
||||
"phpseclib/phpseclib": "^2.0.47",
|
||||
"phpseclib/phpseclib": "^3.0.46",
|
||||
"jbroadway/urlify": "^1.2",
|
||||
"chillerlan/php-qrcode": "^4.3",
|
||||
"chillerlan/php-qrcode": "^5.0.3",
|
||||
"spomky-labs/otphp": "^11.1",
|
||||
"patrickschur/language-detection": "^5.3",
|
||||
"stephenhill/base58": "^1.1",
|
||||
"mmccook/php-json-canonicalization-scheme": "^1.0",
|
||||
"scssphp/scssphp": "^1.12",
|
||||
"scssphp/scssphp": "^2.0.1",
|
||||
"twbs/bootstrap-icons": "^1.11",
|
||||
"mikespub/php-epub-meta": "^2.3"
|
||||
"macgirvin/http-message-signer": "^0.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-yaml": "*",
|
||||
@@ -75,6 +75,11 @@
|
||||
"Zotlabs\\": "Zotlabs/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Zotlabs\\Tests\\Unit\\": "tests/unit/"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"config": {
|
||||
"notify-on-install": false,
|
||||
|
||||
2586
composer.lock
generated
2586
composer.lock
generated
File diff suppressed because it is too large
Load Diff
428
doc/LICENSE
Normal file
428
doc/LICENSE
Normal file
@@ -0,0 +1,428 @@
|
||||
Attribution-ShareAlike 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-ShareAlike 4.0 International Public
|
||||
License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-ShareAlike 4.0 International Public License ("Public
|
||||
License"). To the extent this Public License may be interpreted as a
|
||||
contract, You are granted the Licensed Rights in consideration of Your
|
||||
acceptance of these terms and conditions, and the Licensor grants You
|
||||
such rights in consideration of benefits the Licensor receives from
|
||||
making the Licensed Material available under these terms and
|
||||
conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. BY-SA Compatible License means a license listed at
|
||||
creativecommons.org/compatiblelicenses, approved by Creative
|
||||
Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
e. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
g. License Elements means the license attributes listed in the name
|
||||
of a Creative Commons Public License. The License Elements of this
|
||||
Public License are Attribution and ShareAlike.
|
||||
|
||||
h. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
i. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
k. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
l. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
m. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. Additional offer from the Licensor -- Adapted Material.
|
||||
Every recipient of Adapted Material from You
|
||||
automatically receives an offer from the Licensor to
|
||||
exercise the Licensed Rights in the Adapted Material
|
||||
under the conditions of the Adapter's License You apply.
|
||||
|
||||
c. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
b. ShareAlike.
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share
|
||||
Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter's License You apply must be a Creative Commons
|
||||
license with the same License Elements, this version or
|
||||
later, or a BY-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the
|
||||
Adapter's License You apply. You may satisfy this condition
|
||||
in any reasonable manner based on the medium, means, and
|
||||
context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms
|
||||
or conditions on, or apply any Effective Technological
|
||||
Measures to, Adapted Material that restrict exercise of the
|
||||
rights granted under the Adapter's License You apply.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material,
|
||||
including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
||||
|
||||
142
doc/de/SUMMARY.md
Normal file
142
doc/de/SUMMARY.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# Summary
|
||||
|
||||
- [Über](./about.md)
|
||||
- [Grundlegende Konzepte von Hubzilla](./basicconcepts.md)
|
||||
- [Funktionen](./functions.md)
|
||||
- [Glossar](./glossary.md)
|
||||
- [Oberfläche / Bezeichnungen](ui.md)
|
||||
- [Benutzerhandbuch](./usermanual/overview.md)
|
||||
- [Anmeldung / Registrierung](./usermanual/registration.md)
|
||||
- [Konten, Profile, Kanäle](./usermanual/accounts_profiles_channels_basics.md)
|
||||
- [Kanäle](./usermanual/channels.md)
|
||||
- [Kanäle erstellen](./usermanual/create_channels.md)
|
||||
- [Kanalrollen](./usermanual/channel_roles.md)
|
||||
- [Profile](./usermanual/profiles.md)
|
||||
- [Einstellungen](./usermanual/settings.md)
|
||||
- [Konto-Einstellungen](./usermanual/account_settings.md)
|
||||
- [Kanal-Einstellungen](./usermanual/channel_settings.md)
|
||||
- [Privacy-Einstellungen](./usermanual/privacy_settings.md)
|
||||
- [Anzeige-Einstellungen](./usermanual/display_settings.md)
|
||||
- [Klon-Adressen verwalten](./usermanual/channel_locations.md)
|
||||
- [Stream-Einstellungen](./usermanual/stream_settings.md)
|
||||
- [Zusätzliche Funktionen (verborgene Einstellungen)](./usermanual/additional_features.md)
|
||||
- [Verbinden mit Kanälen](./usermanual/connecting_with_channels.md)
|
||||
- [Posten](./usermanual/posting.md)
|
||||
- [Kommentieren](./usermanual/commenting.md)
|
||||
- [Bilder einfügen](./usermanual/insert_images.md)
|
||||
- [bbCode](./usermanual/bbcode.md)
|
||||
- [Das Grid](./usermanual/the_grid.md)
|
||||
- [Der Stream](./usermanual/the_stream.md)
|
||||
- [Mit Postings interagieren](./usermanual/interact.md)
|
||||
- [Repeat](./usermanual/repeat.md)
|
||||
- [Teilen](./usermanual/share.md)
|
||||
- [Link zur Quelle](./usermanual/link_to_source.md)
|
||||
- [In Ordner speichern](./usermanual/save_to_folder.md)
|
||||
- [Markierungsstatus (Stern) umschalten](./usermanual/toggle_star_status.md)
|
||||
- [Quellcode anzeigen](./usermanual/show_source_code.md)
|
||||
- [Unterhaltung folgen / nicht mehr folgen](./usermanual/follow_conversation.md)
|
||||
- [Löschen](./usermanual/delete.md)
|
||||
- [Konversationsmerkmale](./usermanual/conversation_features.md)
|
||||
- [Inhaltsfilter](./usermanual/content_filters.md)
|
||||
- [Öffentlicher Beitrags-Stream](./usermanual/public_stream.md)
|
||||
- [Apps](./usermanual/apps.md)
|
||||
- [wichtige Apps](./usermanual/important_apps.md)
|
||||
- [Verbindungen](./usermanual/connections.md)
|
||||
- [Verbindungs-Editor](./usermanual/connection_editor.md)
|
||||
- [Diaspora-Kompatibilität](./usermanual/diaspora_compat.md)
|
||||
- [Verzeichnis](./usermanual/directory.md)
|
||||
- [Erweiterte Verzeichnissuche](./usermanual/AdvancedSearch.md)
|
||||
- [Kanäle blockieren/ignorieren/archivieren/verstecken](./usermanual/blocking_channels.md)
|
||||
- [Superblock](./usermanual/superblock.md)
|
||||
- [Berechtigungen](./usermanual/permissions.md)
|
||||
- [Berechtigungen für Inhalte](./usermanual/permissions_content.md)
|
||||
- [Berechtigungen - Benutzerdefinierte Kanalrollen](./usermanual/permissions_channel_roles.md)
|
||||
- [Berechtigungen - Kontaktrollen](./usermanual/permissions_contact_roles.md)
|
||||
- [Direktnachrichten](./usermanual/direct_messages.md)
|
||||
- [Erwähnungen](./usermanual/mentions.md)
|
||||
- [Tags](./usermanual/tags.md)
|
||||
- [Bookmarks](./usermanual/bookmarks.md)
|
||||
- [Suche](./usermanual/search.md)
|
||||
- [Artikel](./usermanual/article.md)
|
||||
- [Dateien](./usermanual/files.md)
|
||||
- [Fotos](./usermanual/photos.md)
|
||||
- [Cloudspeicher](./usermanual/cloud_storage.md)
|
||||
- [Galerie](./usermanual/gallery.md)
|
||||
- [Chaträume](./usermanual/chat_rooms.md)
|
||||
- [Gastzugang](./usermanual/guest_access.md)
|
||||
- [Privacy Gruppen](./usermanual/privacy_groups.md)
|
||||
- [Kalender](./usermanual/calendar.md)
|
||||
- [Adressbuch](./usermanual/addressbook.md)
|
||||
- [Wikis](./usermanual/wikis.md)
|
||||
- [Inhaltswarnung/NSFW](./usermanual/NSFW.md)
|
||||
- [Klonen](./usermanual/clone.md)
|
||||
- [Webseiten](./usermanual/websites.md)
|
||||
- [Comanche Seitenbeschreibungssprache](./usermanual/comanche.md)
|
||||
- [Verschlüsselung](./usermanual/encryption.md)
|
||||
- [Tipps zum Schutz der Privatsphäre](./usermanual/protection_of_privacy.md)
|
||||
- [Kanal löschen](./usermanual/deleting_channel.md)
|
||||
- [Account löschen](./usermanual/delete_account.md)
|
||||
- [Tutorials](./tutorials/tutorials.md)
|
||||
- [Mit Hubzilla Schritt für Schritt ins Fediverse](./tutorials/step_with_hubzilla.md)
|
||||
- [Hubzilla optisch anpassen](./tutorials/customise_look.md)
|
||||
- [Ein abgeleitetes Thema erstellen](./tutorials/DerivedTheme1.md)
|
||||
- [Handbuch für Administratoren](./adminmanual/manual_for_administrators.md)
|
||||
- [Wo Sie weitere Hilfe finden](./adminmanual/further_help.md)
|
||||
- [Bevor Sie beginnen](./adminmanual/before_you_start.md)
|
||||
- [Installation](./adminmanual/installation.md)
|
||||
- [Anforderungen](./adminmanual/installation_requirements.md)
|
||||
- [Manuelle Installation](./adminmanual/manual_installation.md)
|
||||
- [Automatisierte Installation über das Shell-Skript .homeinstall](./adminmanual/automated_installation.md)
|
||||
- [Installation mittels Docker](./adminmanual/Installation_using_docker.md)
|
||||
- [Empfohlene Addons](./adminmanual/recommended_addons.md)
|
||||
- [Föderations Addons](./adminmanual/federation_addons.md)
|
||||
- [Probleme nach einer Aktualisierung](./adminmanual/problems-following-an-update.md)
|
||||
- [Service-Klassen](./adminmanual/service_classes.md)
|
||||
- [Verwaltung der Themen](./adminmanual/theme_management.md)
|
||||
- [Erstellen von Seitenvorlagen](./adminmanual/Creating-Templates.md)
|
||||
- [Hubzilla-Entwicklung - ein Leitfaden für das Schemasystem](./adminmanual/Schema-development.md)
|
||||
- [Grundlegende Widgets](./adminmanual/Widgets.md)
|
||||
- [Kanal-Verzeichnis](./adminmanual/channel_directory.md)
|
||||
- [Primäres Verzeichnis](./adminmanual/Primary-Directory.md)
|
||||
- [Administration](./adminmanual/administration.md)
|
||||
- [Fehlersuche](./adminmanual/troubleshooting.md)
|
||||
- [Hub-Snapshot-Tools](./adminmanual/hub_snapshot_tools.md)
|
||||
- [Datenbank](./adminmanual/database.md)
|
||||
- [Erweiterte Konfigurationen für Administratoren](./adminmanual/advanced_configurations.md)
|
||||
- [CLI-Tools (utils)](./adminmanual/CLI_tools.md)
|
||||
- [Datei-Synchronisation und Klonen](./adminmanual/filesync.md)
|
||||
- [Nomad - Ein Überblick auf oberer Ebene](./adminmanual/Nomad---A-High-Level-Overview.md)
|
||||
- [Admin FAQ](./adminmanual/faq_admins.md)
|
||||
- [Entwickler](./develmanual/developers_guide.md)
|
||||
- [Wer ist ein Hubzilla-Entwickler? Sollte ich das lesen?](./develmanual/who_is_a_hubzilla_developer.md)
|
||||
- [Sie möchten Code beisteuern?](./develmanual/dev_beginner.md)
|
||||
- [Versionen und Releases](./develmanual/versions.md)
|
||||
- [Git-Repository-Zweige](./develmanual/git_repository.md)
|
||||
- [Git für Nicht-Entwickler](./develmanual/git_for_non_developers.md)
|
||||
- [Tools und Arbeitsabläufe für Entwickler](./develmanual/tools_workflows.md)
|
||||
- [Dokumentation erstellen](./develmanual/doco.md)
|
||||
- [Übersetzungen](./develmanual/translations.md)
|
||||
- [Lizenzvergabe](./develmanual/licensing.md)
|
||||
- [Codierungsstil](./develmanual/coding_style.md)
|
||||
- [Dateisystem-Layout](./develmanual/file_system_layout.md)
|
||||
- [Hubzilla-Entwicklung - einige nützliche Grundfunktionen](./develmanual/dev-function-overview.md)
|
||||
- [Erstellen von Plugins/Addons für Hubzilla](./develmanual/Plugins.md)
|
||||
- [Testen](./develmanual/testing.md)
|
||||
- [Erstellen von Protokoll- Föderationsdiensten](./develmanual/federate.md)
|
||||
- [Verhaltenskodex für Mitwirkende](./develmanual/code_of_conduct.md)
|
||||
- [Unser Versprechen](./develmanual/our_pledge.md)
|
||||
- [Unsere Standards](./develmanual/our_standards.md)
|
||||
- [Unsere Verantwortlichkeiten](./develmanual/our_responsibilities.md)
|
||||
- [Geltungsbereich](./develmanual/scope.md)
|
||||
- [Durchsetzung](./develmanual/enforcement.md)
|
||||
- [Namensnennung](./develmanual/attribution.md)
|
||||
- [Das Nomad Protokoll](./develmanual/nomad_protocol.md)
|
||||
- [Technische Einführung](./develmanual/technical_introduction.md)
|
||||
- [Magic Auth](./develmanual/magic_auth.md)
|
||||
- [Nomad-Strukturen](./develmanual/nomad_structures.md)
|
||||
- [Zot API](./develmanual/API.md)
|
||||
- [Hooks](./develmanual/hooks.md)
|
||||
- [Noch zu organisierende Informationen](./develmanual/unorganized.md)
|
||||
- [Das Hubzilla-Projekt](./the_hubzilla_project.md)
|
||||
- [Credits](./credits.md)
|
||||
- [Über diesen Hub](./platzhalter.md)
|
||||
88
doc/de/about.md
Normal file
88
doc/de/about.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Was ist Hubzilla?
|
||||
|
||||
Hubzilla ist ein dezentralisiertes Kommunikationsnetzwerk mit dem Ziel, Kommunikationsmöglichkeiten bereitzustellen, die Zensur umgehen, die Privatsphäre respektieren und somit frei sind von den Einschränkungen, die die heutigen kommerziellen Kommunikationsgiganten uns auferlegen. Diese stellen in erster Linie Spionagenetzwerke für zahlende Kunden aller Art zur Verfügung und monopolisieren und zentralisieren das ganze Internet – was ursprünglich eben gerade nicht unter den revolutionären Zielen war, die einst zum World Wide Web führten.
|
||||
|
||||
Hubzilla ist frei, kostenlos und Open Source. Es wurde entwickelt, um auf einem Raspberry Pi ebenso zu laufen wie auf den größten AMD- und Intel-Xeon-Multiprozessor-Servern. Es kann für die Kommunikation zwischen einigen wenigen Einzelpersonen genutzt werden oder viele tausend Leute und mehr miteinander verbinden.
|
||||
|
||||
Ein weiteres Ziel ist es, von Können und Ressourcen unabhängig zu sein. Hubzilla ist für den einfachen Computernutzer ebenso leicht bedienbar wie für Systemadministratoren und Entwickler.
|
||||
|
||||
Wie Du es benutzt hängt davon ab, wie Du es benutzen *willst.*
|
||||
|
||||
Hubzilla ist in PHP geschrieben, dadurch ist es einfach, sie auf jedweder heutigen Hosting-Plattform zu installieren, inklusive Self-Hosting zu Hause, auf Shared Servern oder auf virtuellen und dedizierten Servern.
|
||||
|
||||
Mit anderen Worten, Hubzilla kann auf jeder Plattform laufen, die einen Web-Server, eine MySQL-kompatible Datenbank und PHP mitbringt.
|
||||
|
||||
---
|
||||
|
||||
## Grundlegende Konzepte und Funktionen von Hubzilla
|
||||
|
||||
|
||||
|
||||
### Kanäle (im Sinne von Identitäten im Gegensatz zu einer App)
|
||||
|
||||
Als Nutzer (d. h. als Privatperson oder als Verein) können Sie eine oder mehrere Web-**Identitäten** erstellen. Die Webpräsenz einer Identität wird innerhalb von Hubzilla gebündelt: Ein Besucher der Web-Identität sieht Inhalte, die mit dieser Identität in Verbindung stehen, an einem Ort, der über das Hauptmenü *Apps* für diese Identität verfügbar ist.
|
||||
|
||||
Intern, innerhalb der Software, wird eine Identität als „Kanal“ bezeichnet. Für einen Besucher bedeutet das Wort „Kanal“ jedoch **eine** bestimmte App, die zu dieser Identität gehört, nämlich die **Pinnwand**, auf der die (möglicherweise) föderierten Beiträge der Identität in einer zeitachsenbasierten Timeline angezeigt werden.
|
||||
|
||||
Im Folgenden verstehen wir Kanäle als Identitäten: Als angemeldeter Benutzer können Sie zwischen Ihren Kanälen wechseln, um die Inhalte für jeden Kanal zu bearbeiten, d. h. Beiträge zu veröffentlichen oder ein oder mehrere Kanalprofile, Websites, Wiki-Seiten und mehr zu erstellen. Pro Kanal können Sie auch Dateien in einer Cloud verwalten, Fotos mit Tags versehen und benennen und die Fotos in einer Webgalerie anzeigen. Ereignisse des Kanals können in einem Kalender angezeigt werden.
|
||||
|
||||
|
||||
|
||||
### Dezentrales Netzwerk: Zugriff über Grenzen hinweg (Zot/Nomad) vs. Bereitstellung über Grenzen hinweg (Zot/Nomad, ActivityPub und Diaspora)
|
||||
|
||||
Wenn dies erlaubt ist, verbinden sich Identitäten auf Hubzilla über Server- und Verwaltungsgrenzen hinweg über das Kommunikationsprotokoll Zot/Nomad (und, sofern von Ihrem Server bereitgestellt, auch über die Protokolle ActivityPub und Diaspora).
|
||||
|
||||
Mit Ausnahme von Beiträgen/Nachrichten bleiben alle veröffentlichten Inhalte lokal auf Ihrem Server. Sie können Inhalte zwar öffentlich veröffentlichen, aber auch lokale Inhalte nur mit bestimmten Verbindungen teilen. Letzteres ist nur mit Verbindungen über Zot/Nomad (also mit Identitäten auf Hubzilla und Streams) möglich.
|
||||
|
||||
|
||||
|
||||
### Zugriffskontrolle
|
||||
|
||||
Ihre lokalen Inhalte können von den Zot/Nomad-basierten Verbindungen „besucht“ werden, denen Sie die entsprechende Berechtigung erteilt haben. Indem Sie Ihre Verbindungen Verbindungslisten (sogenannten „Datenschutzgruppen“) zuordnen, können Sie allen Mitgliedern dieser Liste Zugriff auf bestimmte Inhalte gewähren.
|
||||
|
||||
Sie können Beiträge/Nachrichten (auch über die Protokolle ActivityPub oder Disaspora) an eine Verbindung, an eine Datenschutzgruppe oder an die Öffentlichkeit senden, indem Sie eine Zugriffskontrollliste verwenden.
|
||||
|
||||
Es ist möglich, eine Dauer für das Ablaufen eines Beitrags/einer Nachricht festzulegen. Auf diese Weise können Sie den Zugriff zeitlich begrenzen.
|
||||
|
||||
|
||||
|
||||
### Fernauthentifizierung
|
||||
|
||||
„Kennst du mich? – Ja, ich kenne dich, willkommen!“
|
||||
Der Zugriff auf nicht öffentliche Inhalte auf einem Remote-Server sollte nur möglich sein, wenn du dich gegenüber diesem Server authentifizieren kannst. Fediverse-Software, die nur das ActivityPub- oder das Diaspora-Protokoll verwendet, kann jedoch nur Konten vom lokalen Server authentifizieren.
|
||||
Das Zot-Protokoll hingegen verfügt über einen integrierten Mechanismus namens MagicAuth, der es einem Server ermöglicht, Identitäten, die auf einem anderen (entfernten) Server registriert sind, Zugriff auf Inhalte und Aktionen zu gewähren oder zu verweigern.
|
||||
|
||||
|
||||
|
||||
### Nomadische Identität
|
||||
|
||||
Das Zot/Nomad-Protokoll ermöglicht es, Ihre Kanäle von dem Hub zu trennen, auf dem Sie sie erstellt haben. Sie können sie auf einen anderen Hub übertragen oder klonen. In diesem Fall existieren die Identität und die Daten des Kanals gleichzeitig an mehreren Orten. Dies sorgt für Ausfallsicherheit der Kanäle, falls ein Hub abgeschaltet wird oder nicht mehr verfügbar ist.
|
||||
|
||||
|
||||
|
||||
### Modulares Ökosystem durch Apps
|
||||
|
||||
Hubzilla stellt für jede Funktion eine separate **App** zur Verfügung, d. h. die Cloud, Fotos, Galerie, Chat, Wiki, Kalender, Kontakte oder die Verbindungs-App. Ein Serveradministrator entscheidet, welche Apps für die Benutzer dieses Servers verfügbar sein sollen. Ein Benutzer kann dann die verfügbaren Apps installieren oder deinstallieren.
|
||||
|
||||
|
||||
|
||||
### Zusammenarbeit
|
||||
|
||||
Die folgenden gemeinsamen privaten Bereiche ermöglichen die Arbeit im Team mit Hubzilla:
|
||||
- Als Benutzer erlauben Sie ausgewählten Verbindungen, Ihre Webseiten und Wiki-Seiten zu lesen und zu bearbeiten.
|
||||
- Erlauben Sie ihnen, Ihre Dateien, Ihren Kalender und Ihre Kontakte über die Weboberfläche (die Cloud-, Kalender- und Kontakt-Apps) oder WebDAV, CalDAV und CardDAV zu lesen und zu bearbeiten.
|
||||
- Verwenden Sie Konversations-Threads (Beiträge), die nur für Ihre Kollaborationsgruppe sichtbar sind, indem Sie die Zugriffskontrollliste entsprechend einstellen.
|
||||
|
||||
|
||||
|
||||
### Cloud-Speicher
|
||||
|
||||
Sie können Dokumente direkt auf Ihrer Website speichern und mit anderen teilen. Öffentlicher, privater oder eingeschränkter Zugriff. Da die Dateien auf Ihrem Domainnamen gespeichert sind, wissen die Empfänger, dass sie von Ihnen stammen.
|
||||
|
||||
|
||||
|
||||
### Teilen vs. Boosten
|
||||
|
||||
Mit Hubzilla können Sie Beiträge anderer Fediverse-Nutzer (erneut) teilen. Das (erneute) Teilen in Hubzilla ist so, als würden Sie Ihren Freunden Jennie und Omar erzählen, was Giaco gesagt hat. Und dann sagen sie: „Cool, das gefällt mir“.
|
||||
|
||||
Hubzilla ermöglicht auch das Boosten. Etwas zu boosten ist so, als würdest du deinen Freunden Jennie und Omar erzählen, was Giaco gesagt hat, während Giaco und alle seine Freunde und seine Familie (die du nicht kennst) zuhören. Giaco und alle seine Freunde und seine Familie können jetzt mit dir sprechen.
|
||||
@@ -1,23 +0,0 @@
|
||||
[h3]Was ist $Projectname?[/h3]
|
||||
|
||||
$Projectname ist ein dezentralisiertes Kommunikationsnetzwerk mit dem Ziel, Kommunikationsmöglichkeiten bereitzustellen, die Zensur umgehen, die Privatsphäre respektieren und somit frei sind von den Einschränkungen, die die heutigen kommerziellen Kommunikationsgiganten uns auferlegen. Diese stellen in erster Linie Spionagenetzwerke für zahlende Kunden aller Art zur Verfügung und monopolisieren und zentralisieren das ganze Internet – was ursprünglich eben gerade nicht unter den revolutionären Zielen war, die einst zum World Wide Web führten.
|
||||
|
||||
$Projectname ist frei, kostenlos und Open Source. Sie wurde entwickelt, um auf einem Raspberry Pi für € 30,– ebenso zu laufen wie auf den größten AMD- und Intel-Xeon-Multiprozessor-Servern. Es kann für die Kommunikation zwischen einigen wenigen Einzelpersonen genutzt werden oder viele tausend Leute und mehr miteinander verbinden.
|
||||
|
||||
Ein weiteres Ziel ist es, von Können und Ressourcen unabhängig zu sein. $Projectname ist für den einfachen Computernutzer ebenso leicht bedienbar wie für Systemadministratoren und Entwickler.
|
||||
|
||||
Wie Du es benutzt hängt davon ab, wie Du es benutzen [i]willst.[/i]
|
||||
|
||||
$Projectname ist in PHP geschrieben, dadurch ist es einfach, sie auf jedweder heutigen Hosting-Plattform zu installieren, inklusive Self-Hosting zu Hause, auf Shared Servern wie bei [url=https://uberspace.de/]Uberspace[/url], [url=http://mediatemple.com/]Media Temple[/url] und [url=http://www.dreamhost.com/]Dreamhost[/url], oder auf virtuellen und dedizierten Servern, wie es sie zum Beispiel bei [url=https://www.linode.com]Linode[/url], [url=http://greenqloud.com]GreenQloud[/url] oder [url=https://aws.amazon.com]Amazon AWS[/url] gibt.
|
||||
|
||||
Mit anderen Worten, $Projectname kann auf jeder Plattform laufen, die einen Web-Server, eine MySQL-kompatible Datenbank und PHP mitbringt.
|
||||
|
||||
Dabei bietet $Projectname einige einzigartige Leckerbissen:
|
||||
|
||||
[b]Ein-Klick-Identifikation:[/b] Du kannst auf andere Server im $Projectname-Netzwerk zugreifen, indem Du einfach auf einen Link dorthin klickst. Die Authentifizierung wird ganz einfach automatisch hinter den Kulissen durchgeführt. Vergiss viele verschiedene Usernamen für verschiedene Seiten und die Passwörter dazu – das tut alles $Projectname für Dich.
|
||||
|
||||
[b]Klone:[/b] Du kannst Deine Online-Identität (oder, wie wir sagen, einen Kanal) klonen. Sie ist nicht mehr länger an einen bestimmten Server, eine Domain oder eine IP-Adresse gebunden. Importiere sie einfach auf einem anderen $Projectname-Server (oder $Projectname-Hub, wie es bei uns heißt) – direkt online oder mit Hilfe eines vorher generierten Exports. Wenn Dein primärer Hub plötzlich nicht mehr online ist, kein Problem, Deine Kontakte, Posts* und Nachrichten* sind automagisch weiterhin unter Deiner geklonten Identität verfügbar und zugreifbar. [i](*: nur Posts und Nachrichten, die nach dem Moment des Klonens erstellt wurden)[/i]
|
||||
|
||||
[b]Privatsphäre:[/b] $Projectname-Identitäten (Zot-IDs) können gelöscht, gesichert/heruntergeladen und geklont werden. Du hast volle Kontrolle über Deine Daten. Wenn Du Dich entscheidest, all Deine Daten und Deine Zot-ID zu löschen, musst Du nur auf einen Link klicken, und sie werden sofort von dem Server gelöscht. Keine Fragen, keine Umstände.
|
||||
|
||||
#include doc/macros/main_footer.bb;
|
||||
103
doc/de/adminmanual/CLI_tools.md
Normal file
103
doc/de/adminmanual/CLI_tools.md
Normal file
@@ -0,0 +1,103 @@
|
||||
### CLI Tools (utils)
|
||||
|
||||
Wer als Administrator Zugang zur Shell hat, kann weitere kleine CLI Tools verwenden, welche sich im Verzeichnis "utils" finden.
|
||||
|
||||
#### addons
|
||||
|
||||
Mit dem Script addons können Sie sich anzeigen lassen, welche Addons installiert und welche vorhanden sind. Außerdem können Sie Addons installieren und deinstallieren, sowie alle Addons neu installieren.
|
||||
|
||||
- `util/addons list`
|
||||
Anzeige aller installierter Addons
|
||||
- `util/addons list all`
|
||||
Anzeige aller Addons , die installiert sind (*) und solcher, die aufgrund von Inkompatibilität deaktiviert sind (!)
|
||||
- `util/addons install foo`
|
||||
Installiere das Addon mit dem Namen "foo"
|
||||
- `util/addons uninstall foo`
|
||||
Deinstalliere das Addon mit dem Namen "foo"
|
||||
- `util/addons reinstall`
|
||||
Reinstalliere alle Addons
|
||||
|
||||
#### admins
|
||||
|
||||
Das Script admins ermöglicht es Ihnen, sich sämtliche Admins des Hub anzeigen zu lassen, sowie weitere Admins hinzuzufügen und bestehende Admins zu entfernen.
|
||||
|
||||
- `util/admins`
|
||||
- `util/admins list`
|
||||
- `util/admins add <account_id>`
|
||||
- `util/admins remove <account_id>`
|
||||
|
||||
#### config / pconfig
|
||||
|
||||
Siehe: [Erweiterte Konfigurationen für Administratoren](/help/de/adminmanual/advanced_configurations.md)
|
||||
|
||||
#### connect
|
||||
|
||||
Mit connect können Sie eine Verbindung zwischen einem Kanal Ihres Hubs mit einem anderen Kanal herstellen.
|
||||
|
||||
- `util/connect <channel_id> <channel@hub>`
|
||||
- `util/connect <channel_address> <channel@hub>`
|
||||
|
||||
#### dcp
|
||||
|
||||
Mit dcp können Sie Dateien in den Store-Bereich eines Kanals auf Ihrem Hub kopieren.
|
||||
|
||||
- `util/dcp <quelle> <zielverzeichnis>` wobei Zielverzeichnis `store/$nickname/path` oder `$nickname/path` sein muss.
|
||||
|
||||
#### dmkdir
|
||||
|
||||
Mit dmkdir können Sie im Store-Bereich eines Kanals auf Ihrem Hub ein Unterverzeichnis anlegen.
|
||||
|
||||
- `util/dmkdir <directory>` wobei Directory `store/$nickname/path/<directory>` oder `$nickname/path/<directory>` sein muss.
|
||||
|
||||
#### fresh (The Freaking REd Shell)
|
||||
|
||||
Dies funktioniert nur unter Unix/Linux. Wenn das readline-Modul installiert ist, verwenden es dieses für die Eingabe, ansonsten liest es nur von stdin und schreibt nach stdout.
|
||||
Die Befehle werden der Reihe nach abgearbeitet, bis der Befehl „exit“, „quit“ oder das Ende der Datei erreicht ist.
|
||||
|
||||
Kommandos:
|
||||
|
||||
- `version`
|
||||
Zeigt die aktuelle Fresh-Version an.
|
||||
- `login <E-Mail-Adresse>`
|
||||
Fragt nach einem Passwort und authentifiziert `<E-Mail-Adresse>` als den aktuellen
|
||||
Benutzer.
|
||||
- `finger <Kanal-Adresse>`
|
||||
Führt einen Lookup von `<Kanal-Adresse>` durch und meldet das Ergebnis.
|
||||
- `channel <Kanal-Nickname>`
|
||||
Schaltet den aktuellen Kanal auf den Kanal mit dem angegebenen Spitznamen um.
|
||||
- `conn [<id1> <id2> ...]`
|
||||
- Ohne Argumente listet dies alle Verbindungen des aktuellen Kanals mit einer ID auf.
|
||||
Wenn IDs angegeben werden, werden die Details der einzelnen Verbindungen angezeigt.
|
||||
|
||||
#### hz
|
||||
|
||||
Einfaches, minimalistisches Kommandozeilentool, um den Status über die API an hubzilla zu senden. Erfordert curl.
|
||||
|
||||
`hz [<Konfigurationsdatei>]`
|
||||
|
||||
hz benötigt eine Konfigurationsdatei. Sie können entweder eine Datei `.hubzilla` verwenden und den Parameter `<Konfigurationsdatei>` weglassen oder eine Konfigurationsdatei unter einem beliebigen Namen im Hubzilla-Verzeichnis erstellen, deren Namen Sie dann bei Aufruf von hz angeben.
|
||||
|
||||
Format der Konfigurationsdatei:
|
||||
|
||||
```
|
||||
USER=<Ihr Benutzername>
|
||||
PASS=<Ihr Passwort>
|
||||
HUB=<Domain Ihres Hubs>
|
||||
```
|
||||
|
||||
Anschließend können Sie Ihr Posting eingeben und die Eingabe mit Strg-D abschließen.
|
||||
|
||||
#### storageconf
|
||||
|
||||
Mit storageconf können Sie den Speicherort für Thumbnails festlegen (Dateisystem oder Datenbank), sowie die aktuelle Konfiguration abfragen.
|
||||
|
||||
- `util/storageconv stats`
|
||||
Zeigt den aktuell eingestellten Status
|
||||
- `util/storageconv fs`
|
||||
Verschiebt die Thumbnails von der Datenbank ins Dateisystem
|
||||
- `util/storageconv db`
|
||||
Verschiebt die Thumbnails vom Dateisystem in die Datenbank
|
||||
|
||||
#### thumbrepair
|
||||
|
||||
thumbrepair erstellt die lokalen Thumbnails neu.
|
||||
79
doc/de/adminmanual/Creating-Templates.md
Normal file
79
doc/de/adminmanual/Creating-Templates.md
Normal file
@@ -0,0 +1,79 @@
|
||||
### Erstellen von Seitenvorlagen
|
||||
|
||||
Für eine Seitenvorlage zur Verwendung mit Comanche sind zwei Dateien erforderlich - eine PHP-Vorlage und eine CSS-Datei. Die Seitenvorlagen müssen vom Systemadministrator Ihrer Website installiert werden.
|
||||
Wählen Sie zunächst einen Namen. In diesem Fall werden wir eine Vorlage erstellen und sie „demo“ nennen.
|
||||
Sie müssen die Dateien „view/php/demo.php“ und „view/css/demo.css“ erstellen, um die PHP-Vorlage bzw. das CSS zu speichern.
|
||||
Um eine bessere Vorstellung von diesem Prozess zu bekommen, schauen wir uns eine bestehende Vorlage an - die „Standard“-Vorlage. Diese wird standardmäßig in der gesamten Anwendung verwendet.
|
||||
|
||||
#### **view/php/default.php**
|
||||
|
||||
```
|
||||
<!DOCTYPE html >
|
||||
<html>
|
||||
<head>
|
||||
<title><?php if(x($page,'title')) echo $page['title'] ?></title>
|
||||
<script>var baseurl=„<?php echo z_root() ?>“;</script>
|
||||
<?php if(x($page,'htmlhead')) echo $page['htmlhead'] ?>
|
||||
</head>
|
||||
<body>
|
||||
<?php if(x($page,'nav')) echo $page['nav']; ?>
|
||||
<aside id=„region_1“><?php if(x($page,'aside')) echo $page['aside']; ?></aside>
|
||||
<section id=„region_2“><?php if(x($page,'content')) echo $page['content']; ?>
|
||||
<div id=„page-footer“></div>
|
||||
<div id=„pause“></div>
|
||||
</abschnitt>
|
||||
<aside id=„region_3“><?php if(x($page,'right_aside')) echo $page['right_aside']; ?></aside>
|
||||
<footer><?php if(x($page,'footer')) echo $page['footer']; ?></footer>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Hier ist die entsprechende CSS-Datei
|
||||
|
||||
#### **view/php/default.css**
|
||||
|
||||
```
|
||||
aside#region_1 {
|
||||
Anzeige: block;
|
||||
Breite: 210px;
|
||||
Position: absolut;
|
||||
oben: 65px;
|
||||
links: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
beiseite input[type='text'] {
|
||||
Breite: 174px;
|
||||
}
|
||||
section {
|
||||
Position: absolut;
|
||||
top: 65px;
|
||||
links: 250px;
|
||||
Anzeige: block;
|
||||
rechts: 15px;
|
||||
padding-bottom: 350px;
|
||||
}
|
||||
```
|
||||
|
||||
Wenn Sie sich diese Definitionen ansehen, fallen Ihnen vielleicht einige Dinge auf:
|
||||
|
||||
- Wir haben kein CSS für die Bereiche „nav“, „right_aside“ oder „footer“ angegeben. In dieser Vorlage werden „nav“ und „footer“ die volle Seitenbreite einnehmen, und wir lassen die Größe und Platzierung dieser Elemente durch das Thema steuern. „right_aside“ wird derzeit nicht verwendet.
|
||||
- Es gibt Elemente auf der Seite wie „page-footer“ und „pause“, für die es keinen sichtbaren Inhalt gibt. Dieser Inhalt wird von Javascript-Elementen stammen.
|
||||
- Unsere Standardvorlage verwendet eine absolute Positionierung. Modernes Webdesign verwendet häufig „float“-Div-Container, so dass bei der Anzeige auf Geräten mit kleinen Bildschirmen in der Regel keine Bildlaufleisten erforderlich sind.
|
||||
|
||||
Um eine neue Vorlage zu entwerfen, ist es am besten, mit einer bestehenden Vorlage zu beginnen und sie nach Wunsch zu ändern. Genau das werden wir hier tun.
|
||||
Die Art und Weise, wie Comanche Inhalte innerhalb einer bestimmten Region bereitstellt, ist die Verwendung eines Region-Tags.
|
||||
|
||||
```
|
||||
[region=aside][widget=profile][/widget][/region]
|
||||
```
|
||||
|
||||
In diesem Beispiel wird ein „Profil“-Widget in der Region „aside“ platziert. In Wirklichkeit wird jedoch der HTML-Code für das Widget in der Code-Variablen **$page['aside']** abgelegt. Unsere Standardseitenvorlage definiert einen Bereich auf der Seite (das CSS positioniert diesen als absolute Seitenleiste) und fügt dann den Inhalt von $page['aside'] ein (falls vorhanden).
|
||||
Wenn Sie also eine Vorlage mit einem Bereich namens „foo“ erstellen wollten, würden Sie einen Platz dafür auf der Seite vorsehen, dann den Inhalt von $page['foo'] dort einfügen, wo Sie ihn verwenden wollen, und dann mit Comanche angeben
|
||||
|
||||
```
|
||||
[region=foo][widget=profile][/widget][/region]
|
||||
```
|
||||
|
||||
und dies würde ein Profil-Widget in der von Ihnen erstellten „foo“-Region platzieren.
|
||||
Verwenden Sie die CSS-Datei, um den Bereich an der gewünschten Stelle auf der Seite zu positionieren und optional seine Größe zu steuern.
|
||||
56
doc/de/adminmanual/Installation_using_docker.md
Normal file
56
doc/de/adminmanual/Installation_using_docker.md
Normal file
@@ -0,0 +1,56 @@
|
||||
### Installation mittels Docker
|
||||
|
||||
Es besteht die Möglichkeit, Hubzilla komfortabel und bequem als Docker-Container zu installieren. Dafür bietet Saiwal ([sk@hub.utsukta.org](https://hub.utsukta.org/channel/sk)) ein vorkonfigurierte Umgebung für einen Hubzilla-Container an.
|
||||
|
||||
Hauptfeatures sind:
|
||||
|
||||
- Einfache Bereitstellung: Verwenden Sie Docker Compose, um eine voll funktionsfähige Hubzilla-Instanz mit nur wenigen Befehlen einzurichten.
|
||||
- Benutzerdefinierte Konfiguration: Passen Sie Ihre Hubzilla-Installation ganz einfach mit Umgebungsvariablen für SMTP, Datenbank und mehr an.
|
||||
- Kontinuierliche Updates: Das Docker-Image ist so aufgebaut, dass es einfach aktualisiert werden kann, wenn neue Änderungen am Hubzilla-Kern oder seinen Abhängigkeiten vorgenommen werden.
|
||||
- SMTP-Integration: Integrierte Unterstützung für den Versand von E-Mails mit ssmtp, wodurch die Konfiguration von E-Mail-Benachrichtigungen für Ihre Hubzilla-Instanz erleichtert wird.
|
||||
|
||||
Das Repository für den Container befindet sich hier: [**skprg/hubzilla-docker**](https://github.com/skprg/hubzilla-docker)
|
||||
|
||||
#### Das Image von Grund auf neu erstellen
|
||||
|
||||
- Klonen Sie das Repository:
|
||||
|
||||
```
|
||||
git clone https://github.com/skprg/hubzilla-docker.git
|
||||
cd hubzilla-docker
|
||||
```
|
||||
|
||||
- Konfigurieren Sie Ihre Umgebung: Aktualisieren Sie die Datei `docker-compose.yml` mit Ihren SMTP- und anderen Einstellungen.
|
||||
- Erstellen und führen Sie den Container aus:
|
||||
|
||||
```
|
||||
docker-compose up --build -d
|
||||
```
|
||||
|
||||
#### Vorgefertigtes Image verwenden
|
||||
|
||||
- Ersetzen Sie die folgenden Zeilen in `docker-compose.yml`
|
||||
|
||||
```
|
||||
build:
|
||||
context: .
|
||||
Dockerfile: Dockerfile
|
||||
```
|
||||
|
||||
mit
|
||||
|
||||
```
|
||||
image: ghcr.io/skprg/hubzilla-docker:latest
|
||||
```
|
||||
|
||||
- Starten Sie den Container:
|
||||
|
||||
```
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Greifen Sie auf Ihre Hubzilla-Instanz zu: Navigieren Sie zu http://localhost (oder der entsprechenden URL), um Ihre Hubzilla-Instanz anzuzeigen.
|
||||
|
||||
#### Weitere Hinweise / Update / Tipps
|
||||
|
||||
Weitere Hinweise, Upgrade-Anweisungen und Tipps finden Sie im oben verlinkten Repository.
|
||||
111
doc/de/adminmanual/Nomad---A-High-Level-Overview.md
Normal file
111
doc/de/adminmanual/Nomad---A-High-Level-Overview.md
Normal file
@@ -0,0 +1,111 @@
|
||||
### Nomad - Ein Überblick auf oberer Ebene
|
||||
|
||||
Hier ist eine allgemeine Beschreibung der Funktionsweise von Nomad.
|
||||
|
||||
In diesem Beispiel wird „Indigo“ eine öffentliche Nachricht von seiner Website „podunk.edu“ aus versenden. „Nickordo„ ist ein Empfänger auf einer anderen Website (“example.com").
|
||||
|
||||
Indigo stellt seine Nachricht zuerst auf podunk.edu ein. podunk.edu schaut nach, wer die Nachricht erhalten soll und findet Nickordo. Nickordo postet normalerweise von example.com aus, also fügen wir dieses Ziel zu unserer Liste der Empfänger hinzu. Wir können auch andere Ziele für Nickordo und alle anderen, die Indigos Beiträge verfolgen, hinzufügen.
|
||||
|
||||
In diesem Beispiel stellen wir fest, dass wir nur einen bekannten Empfänger an einem bekannten Ort haben.
|
||||
|
||||
Wir senden ein Paket an example.com:
|
||||
|
||||
|
||||
|
||||
{
|
||||
"type":"notify",
|
||||
"sender":{
|
||||
"guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA",
|
||||
"guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q",
|
||||
"url":"http:\/\/podunk.edu",
|
||||
"url_sig":"T8Bp7j5DHHhQDCFcAHXfuhUfGk2P3inPbImwaXXF1xJd3TGgluoXyyKDx6WDm07x0hqbupoAoZB1qBP3_WfvWiJVAK4N1FD77EOYttUEHZ7L43xy5PCpojJQmkppGbPJc2jnTIc_F1vvGvw5fv8gBWZvPqTdb6LWF6FLrzwesZpi7j2rsioZ3wyUkqb5TDZaNNeWQrIEYXrEnWkRI_qTSOzx0dRTsGO6SpU1fPWuOOYMZG8Nh18nay0kLpxReuHCiCdxjXRVvk5k9rkcMbDBJcBovhiSioPKv_yJxcZVBATw3z3TTE95kGi4wxCEenxwhSpvouwa5b0hT7NS4Ay70QaxoKiLb3ZjhZaUUn4igCyZM0h6fllR5I6J_sAQxiMYD0v5ouIlb0u8YVMni93j3zlqMWdDUZ4WgTI7NNbo8ug9NQDHd92TPmSE1TytPTgya3tsFMzwyq0LZ0b-g-zSXWIES__jKQ7vAtIs9EwlPxqJXEDDniZ2AJ6biXRYgE2Kd6W_nmI7w31igwQTms3ecXe5ENI3ckEPUAq__llNnND7mxp5ZrdXzd5HHU9slXwDShYcW3yDeQLEwAVomTGSFpBrCX8W77n9hF3JClkWaeS4QcZ3xUtsSS81yLrp__ifFfQqx9_Be89WVyIOoF4oydr08EkZ8zwlAsbZLG7eLXY"
|
||||
},
|
||||
"callback":"\/post",
|
||||
"version":1,
|
||||
"secret":"1eaa6613699be6ebb2adcefa5379c61a3678aa0df89025470fac871431b70467"
|
||||
}
|
||||
|
||||
In diesem Paket steht das Folgende:
|
||||
|
||||
Ich bin Indigo und hier ist der Beweis. Ich poste von podunk.edu und hier ist der Beweis. Ich habe ein Paket für Sie. Die Kontrollnummer lautet „1eaa6613....“.
|
||||
|
||||
Example.com nimmt dieses Paket an und sagt: „Moment mal - ich kenne Sie nicht. Ich möchte beweisen, wer du bist.“ Example.com stellt also eine Verbindung zu podunk.edu über eine „bekannte URL“ her, die wir für diesen Zweck verwenden, und sucht nach der oben genannten „guid“. Es sollte eine Reihe von Informationen zurückgeben, darunter auch einen öffentlichen Schlüssel. Example.com verwendet diesen Schlüssel, um die Signaturen in der Nachricht zu überprüfen und festzustellen, ob es tatsächlich eine Person namens Indigo bei podunk.edu gibt. Wir müssen dies nur einmal tun. (Beachten Sie, dass Indigo von jedem Ort aus posten kann. Wir müssen nur beweisen, dass es sich um Indigo handelt und dass Indigo beweisen kann, dass er von einem anderen Standort aus postet).
|
||||
|
||||
Dann trennt example.com die Verbindung und weist darauf hin, dass eine Nachricht auf podunk.edu wartet. Entweder sofort oder immer dann, wenn der Drang besteht (je nachdem, wie wichtig Indigo für jemanden auf dieser Website ist), „ruft“ example.com podunk.edu an. Die Nachricht lautet in etwa so:
|
||||
|
||||
|
||||
|
||||
{
|
||||
"type":"pickup",
|
||||
"url":"http:\/\/example.com",
|
||||
"callback_sig":"teE1_fLIqfyeCuZY4iS7sNU8jUlUuqYOYBiHLarkC99I9K-uSr8DAwVW8ZPZRK-uYdxRMuKFb6cumF_Gt9XjecCPBM8HkoXHOi_VselzJkxPwor4ZPtWYWWaFtRfcAm794LrWjdz62zdESTQd2JJIZWbrli1sUhK801BF3n0Ye6-X1MWhy9EUTVlNimOeRipcuD_srMhUcAXOEbLlrugZ8ovy2YBe6YOXkS8jj0RSFjsOduXAoVhQmNpcobSYsDvaQS3e3MvE6-oXE602zGQhuNLr7DIMt9PCdAeQo-ZM-DHlZGCkGk4O2oQFCXFzGPqLUMWDACGJfTfIWGoh_EJqT_SD5b_Yi_Wk9S1lj7vb-lmxe5JuIf7ezWzHoBT8vswnZxPYlidH2i9wapdzij9il_qqcCWWHIp7q_XkY_Zj52Z4r4gdmiqM-8y1c_1SDX7hrJFRwqL_PKFbEvyi5nMWTEzqp55Tay5Woiv19STK_H_8ufFfD9AOkYnk6rIOMsk9dn3a5tAFpDRyRndXkBWAXwiJjiND2zjue7BFu7Ty40THXcfYRh1a5XrAXcaGeYuagg-8J9tAufu9_LY3qGazFg8kRBVMOn4M8DRKSIhKj7z4MnbYL0s09gREojy4jqWO3VkaOjP2jUGzoPuUDLasudE1ehWFq0K_MTQNavgmp8",
|
||||
"callback":"http:\/\/example.com\/post",
|
||||
"secret":"1eaa6613699be6ebb2adcefa5379c61a3678aa0df89025470fac871431b70467",
|
||||
"secret_sig":"O7nB4_UJHBXi28Suwl9LBZF9hI_9KGVTgehnUlWF1oYMNRnBbVHB9lzUfAoalvp3STbU3xJbtD_S58tv6MfV7J5j2V_S1W5ex3dulmDGB8Pt_7Fe5mbEPmjQFcfv3Eg5dUjYIuDl0TDScfrHyImj7RZIWHbwd7wWVoMzzDa_o33klpYmKZCBvObCh55bRrlFkXZs_dRuOiPwkfX0C6_XES4OyOIYl45V30rdhmf-STrf4L9dKYy_axQ12RIwRcKychvVLwlUJn3bn9lgNXRRU_HTne-09OPcJbUOdcD3DkFoKOxMULBNKPHzsCau0ICYug7S0EP6LpCom_mW78s08LyVA1vYeFZjevBCiGecj57yIAQDYi6_rpWJfihYaWHRN0oqtScUR4Bdf0bQbEHxMs4zAtrOAxfyJCbi6U1pfnGgzXzB9ulOYGnVGNTF7Ey4K7FOZIBtk0ILY2JfvBUaVvVs8ttagOOHmhWhnbCvrnOFlkNdlce7zoJCSUJENUOCYmTRfwB_Jno5fAzRnrsYU3_Z-l1mzniU_OmUPz8mPEh7PwhkqAiVlyaM-q15gn7l2lAIDk9kp2X_iCme7v4V0ADN_DbpaI_0-6mPw5HLbKrCsA-sxlSMB4DO4lDCHYkauj0l25sbfroRWB_hax1O4Q0oWyOlVJLUqEC5nuUJCCE"
|
||||
}
|
||||
|
||||
Was diese Nachricht aussagt, ist: Hier ist example.com, ich habe einen Beweis, und ich bin hier, um ein Paket abzuholen. Hier ist die Sendungsverfolgungsnummer, und hier ist der Beweis, dass dies die Sendungsverfolgungsnummer ist, die Sie vermutlich an example.com gesendet haben.
|
||||
|
||||
Gut genug. Podunk.edu überprüft die Geschichte und tatsächlich, es ist example.com, und ja, da wartet ein Paket mit dieser Kontrollnummer. Hier ist das Paket...
|
||||
|
||||
|
||||
|
||||
{
|
||||
"success":1,
|
||||
"pickup":{
|
||||
"notify":{
|
||||
"type":"notify",
|
||||
"sender":{
|
||||
"guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA",
|
||||
"guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q",
|
||||
"url":"http:\/\/z.podunk.edu",
|
||||
"url_sig":"T8Bp7j5DHHhQDCFcAHXfuhUfGk2P3inPbImwaXXF1xJd3TGgluoXyyKDx6WDm07x0hqbupoAoZB1qBP3_WfvWiJVAK4N1FD77EOYttUEHZ7L43xy5PCpojJQmkppGbPJc2jnTIc_F1vvGvw5fv8gBWZvPqTdb6LWF6FLrzwesZpi7j2rsioZ3wyUkqb5TDZaNNeWQrIEYXrEnWkRI_qTSOzx0dRTsGO6SpU1fPWuOOYMZG8Nh18nay0kLpxReuHCiCdxjXRVvk5k9rkcMbDBJcBovhiSioPKv_yJxcZVBATw3z3TTE95kGi4wxCEenxwhSpvouwa5b0hT7NS4Ay70QaxoKiLb3ZjhZaUUn4igCyZM0h6fllR5I6J_sAQxiMYD0v5ouIlb0u8YVMni93j3zlqMWdDUZ4WgTI7NNbo8ug9NQDHd92TPmSE1TytPTgya3tsFMzwyq0LZ0b-g-zSXWIES__jKQ7vAtIs9EwlPxqJXEDDniZ2AJ6biXRYgE2Kd6W_nmI7w31igwQTms3ecXe5ENI3ckEPUAq__llNnND7mxp5ZrdXzd5HHU9slXwDShYcW3yDeQLEwAVomTGSFpBrCX8W77n9hF3JClkWaeS4QcZ3xUtsSS81yLrp__ifFfQqx9_Be89WVyIOoF4oydr08EkZ8zwlAsbZLG7eLXY"
|
||||
},
|
||||
"callback":"\/post",
|
||||
"version":1,
|
||||
"secret":"1eaa6613699be6ebb2adcefa5379c61a3678aa0df89025470fac871431b70467"
|
||||
},
|
||||
"message":{
|
||||
"message_id":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu",
|
||||
"message_top":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu",
|
||||
"message_parent":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu",
|
||||
"created":"2012-11-20 04:04:16",
|
||||
"edited":"2012-11-20 04:04:16",
|
||||
"title":"",
|
||||
"body":"Hi Nickordo",
|
||||
"app":"",
|
||||
"verb":"post",
|
||||
"object_type":"",
|
||||
"target_type":"",
|
||||
"permalink":"",
|
||||
"location":"",
|
||||
"longlat":"",
|
||||
"owner":{
|
||||
"name":"Indigo",
|
||||
"address":"indigo@podunk.edu",
|
||||
"url":"http:\/\/podunk.edu",
|
||||
"photo":{
|
||||
"mimetype":"image\/jpeg",
|
||||
"src":"http:\/\/podunk.edu\/photo\/profile\/m\/5"
|
||||
},
|
||||
"guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA",
|
||||
"guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q"
|
||||
},
|
||||
"author":{
|
||||
"name":"Indigo",
|
||||
"address":"indigo@podunk.edu",
|
||||
"url":"http:\/\/podunk.edu",
|
||||
"photo":{
|
||||
"mimetype":"image\/jpeg",
|
||||
"src":"http:\/\/podunk.edu\/photo\/profile\/m\/5"
|
||||
},
|
||||
"guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA",
|
||||
"guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Und das ist das Paket (die ursprüngliche Nachricht). Example.com wandelt diese in eine Form um, die von Nickordo eingesehen werden kann, und benachrichtigt Nickordo, dass es eine neue Nachricht gibt. Podunk.edu **könnte** feststellen, dass noch andere Pakete auf example.com warten. Wenn dies der Fall ist, kann es auch alle anderen wartenden Pakete zu diesem Zeitpunkt versenden. Jedes dieser Pakete ist mit der ursprünglichen Sendungsnummer versehen.
|
||||
35
doc/de/adminmanual/Primary-Directory.md
Normal file
35
doc/de/adminmanual/Primary-Directory.md
Normal file
@@ -0,0 +1,35 @@
|
||||
### Primäres Verzeichnis
|
||||
|
||||
Standardmäßig verwendet Hubzilla verfügbare Verzeichnisse im Internet, die Ihnen weltweit verfügbare Kanäle anzeigen.
|
||||
|
||||
Es gibt bestimmte Szenarien, in denen Sie Ihren eigenen Verzeichnis-Server benötigen, mit dem Sie mehrere Hubs verbinden können. Dadurch werden die Kanäle, die in allen Ihren Hubs erscheinen, auf die Kanäle der Hubs beschränkt, die mit Ihrem Verzeichnis-Server verbunden sind.
|
||||
|
||||
#### Anleitungen zum Einrichten eines Hubs als primäres Verzeichnis für eine Reihe von privaten Hubs.
|
||||
|
||||
- Öffnen Sie auf dem Hub, der der Directory Server sein wird, die Datei .htconfig.php und setzen Sie
|
||||
`App::$config['system']['directory_mode'] = DIRECTORY_MODE_PRIMARY;`
|
||||
|
||||
```
|
||||
Standardmäßig sollte dies bereits **DIRECTORY_MODE_NORMAL** sein, also ändern Sie diese Zeile einfach in **DIRECTORY_MODE_PRIMARY**.
|
||||
```
|
||||
|
||||
- Als Nächstes gehen Sie für jeden Hub (einschließlich des Verzeichnisservers) von einem Terminal aus in den Ordner, in dem er installiert ist, und führen Folgendes aus:
|
||||
|
||||
`util/config system directory_realm YOURREALMNAME`
|
||||
(**YOURREALMNAME** kann jeder beliebige Name für Ihren Realm sein)
|
||||
|
||||
dann:
|
||||
|
||||
`util/config system realm_token THEPASSWORD`
|
||||
(**THEPASSWORD** ist das Passwort, das Sie für Ihren Realm verwenden möchten)
|
||||
**HINWEIS:** Verwenden Sie für jeden Hub denselben Realm-Namen und dasselbe Passwort.
|
||||
|
||||
- Führen Sie schließlich für jeden „Client“-Hub (von einem Terminal aus) aus:
|
||||
|
||||
`util/config system directory_server https://theaddressofyourdirectoryserver.com`
|
||||
|
||||
Wenn Sie sich nun das Verzeichnis jedes Hubs ansehen, sollten nur die Kanäle angezeigt werden, die auf den Hubs in Ihrem Realm existieren. Ich habe bisher mit zwei Hubs getestet, und es scheint gut zu funktionieren. Channels, die in jedem Hub erstellt wurden, werden im Primärverzeichnis und anschließend im Verzeichnis aller Client-Hubs angezeigt.
|
||||
|
||||
#### Probleme
|
||||
|
||||
Als ich den ersten Hub erstellte, lief er etwa eine Stunde lang, bevor ich ihn auf PRIMARY_MODE umstellte, und nachdem ich ihn umgestellt hatte, waren noch einige Kanäle aus der gesamten Matrix im Verzeichnis vorhanden. Ich habe sie aus der xchan-Tabelle gelöscht, und das scheint das Problem behoben zu haben.
|
||||
45
doc/de/adminmanual/Schema-development.md
Normal file
45
doc/de/adminmanual/Schema-development.md
Normal file
@@ -0,0 +1,45 @@
|
||||
### Hubzilla-Entwicklung - ein Leitfaden für das Schemasystem
|
||||
|
||||
Ein Schema ist, kurz gesagt, eine Sammlung von Einstellungen für eine Reihe von Variablen, die bestimmte Elemente eines Themes definieren. Ein Schema wird so geladen, als wäre es Teil der config.php und hat Zugang zu allen Informationen. Das bedeutet, dass es identitätsbewusst ist und für einige interessante Dinge verwendet werden kann. Man könnte z. B. die Optionen nach Dienstklassen einschränken oder verschiedenen Mitgliedern unterschiedliche Optionen anbieten.
|
||||
|
||||
Standardmäßig filtern wir nur danach, ob der Expertenmodus aktiviert ist oder nicht. Wenn der Expertenmodus aktiviert ist, werden dem Mitglied alle Optionen angezeigt. Ist dies nicht der Fall, stehen nur Schema, Hintergrundbild, Schriftart und Iconset zur Auswahl.
|
||||
|
||||
Ein Schema wird *erst nach* den persönlichen Einstellungen des Mitglieds geladen. Um einem Mitglied die Möglichkeit zu geben, einen bestimmten Aspekt eines Schemas zu überschreiben, würden Sie daher die folgende Syntax verwenden:
|
||||
|
||||
```
|
||||
if (! $foo)
|
||||
$foo = 'bar';
|
||||
```
|
||||
|
||||
Es gibt jedoch Umstände - insbesondere bei positionalen Elementen -, unter denen es wünschenswert (oder notwendig) sein kann, die Einstellungen eines Mitglieds zu überschreiben. In diesem Fall ist die Syntax noch einfacher:
|
||||
|
||||
```
|
||||
$foo = 'bar';
|
||||
```
|
||||
|
||||
Die Mitglieder werden Ihnen dies jedoch nicht danken, also verwenden Sie es nur, wenn es erforderlich ist.
|
||||
Wenn keine persönlichen Optionen eingestellt sind und kein Schema ausgewählt ist, wird zunächst versucht, ein Schema mit dem Dateinamen „default.php“ zu laden. Diese Datei sollte niemals in ein Thema eingebunden werden. Wenn dies der Fall ist, wird es zu Konflikten kommen, wenn andere ihren Code aktualisieren. Vielmehr sollte dies von den Administratoren für jede Seite einzeln festgelegt werden. default.php und default.css MÜSSEN Symlinks zu bestehenden Schemadateien sein.
|
||||
|
||||
Ihr Schema muss - und sollte - nicht alle diese Werte enthalten. Nur die Werte, die von den Standardwerten abweichen, sollten aufgeführt werden. Dies gibt Ihnen einige sehr mächtige Optionen mit sehr wenigen Zeilen Code.
|
||||
|
||||
Beachten Sie, dass die verfügbaren Optionen von Thema zu Thema unterschiedlich sind. Für das Redbasic-Theme sind folgende Optionen verfügbar:
|
||||
|
||||
- nav_colour Die Farbe der Navigationsleiste. Die Optionen sind rot, schwarz und silber. Alternativ kann man $nav_bg_1, $nav_bg_2, $nav_bg_3 und $nav_bg_4 einstellen, um Farbverläufe und Hover-Effekte zu erzielen.
|
||||
- banner_colour Die Schriftfarbe des Bannerelements. Akzeptiert einen RGB- oder Hex-Wert.
|
||||
- bgcolour Legt die Hintergrundfarbe des Körpers fest. Akzeptiert einen RGB- oder Hex-Wert.
|
||||
- background_image Legt ein Hintergrundbild fest. Akzeptiert eine URL oder einen Pfad.
|
||||
- item_colour Legt die Hintergrundfarbe von Elementen fest. Akzeptiert einen RGB- oder Hex-Wert.
|
||||
- item_opacity Legt die Deckkraft der Elemente fest. Akzeptiert einen Wert von 0,01 bis 1
|
||||
- toolicon_colour Legt die Farbe der Werkzeugsymbole fest. Akzeptiert einen RGB- oder Hex-Wert.
|
||||
- toolicon_activecolour Legt die Farbe der aktiven oder mit dem Mauszeiger gehaltenen Werkzeugsymbole fest.
|
||||
- font_size Legt die Größe der Schriftarten in Artikeln und Beiträgen fest. Akzeptiert px oder em.
|
||||
- body_font_size Legt die Größe der Schriftarten auf der Body-Ebene fest. Akzeptiert px oder em.
|
||||
- font_colour Legt die Farbe der Schrift fest. Akzeptiert einen RGB- oder Hex-Wert.
|
||||
- radius Legt den Radius der Ecken fest. Akzeptiert einen Zahlenwert und ist immer in px.
|
||||
- shadow Legt die Größe der Schatten fest, die bei Inline-Bildern angezeigt werden. Akzeptiert einen numerischen Wert. Hinweis: Schatten werden nicht auf Smileys angewendet.
|
||||
- converse_width Legt die maximale Breite des Inhaltsbereichs in px fest.
|
||||
- nav_min_opacity
|
||||
- top_photo
|
||||
- antwort_foto
|
||||
|
||||
Wenn eine Datei your_schema_name.css gefunden wird, wird der Inhalt dieser Datei an das Ende von style.css angehängt. Dies gibt dem Schema-Entwickler die Möglichkeit, jede Style-Komponente zu überschreiben.
|
||||
99
doc/de/adminmanual/Widgets.md
Normal file
99
doc/de/adminmanual/Widgets.md
Normal file
@@ -0,0 +1,99 @@
|
||||
### Grundlegende Widgets
|
||||
|
||||
Einige/viele dieser Widgets haben Einschränkungen, die die Art der Seite, auf der sie erscheinen können, einschränken oder eine Anmeldung erfordern können
|
||||
|
||||
- clock - zeigt die aktuelle Zeit an
|
||||
- args: military (1 oder 0) - verwendet 24-Stunden-Zeit anstelle von AM/PM
|
||||
- profile - zeigt eine Profil-Seitenleiste auf Seiten an, die Profile laden (Seiten mit Nickname in der URL)
|
||||
- tagcloud - zeigt eine Tagcloud von Webseiten-Elementen an
|
||||
- args: count - Anzahl der Elemente, die zurückgegeben werden sollen (Standardwert 24)
|
||||
- collections - Auswahl der Privatsphärengruppe für den aktuell eingeloggten Kanal
|
||||
- args: mode - eine der Optionen „conversation“, „group“, „abook“ je nach Modul
|
||||
- suggestions - Freundesvorschläge für den aktuell angemeldeten Kanal
|
||||
- follow - zeigt ein Textfeld zum Folgen eines anderen Channels an
|
||||
- notes - privater Notizbereich für den aktuell eingeloggten Kanal, wenn die Funktion private_notes aktiviert ist
|
||||
- savedsearch - Netzwerk-/Matrixsuche mit Speicherung - muss eingeloggt und die savedsearch-Funktion aktiviert sein
|
||||
- filer - Auswahl abgelegter Elemente aus dem Netzwerk/Matrix-Stream - muss eingeloggt sein
|
||||
- archive - Datumsbereichswähler für Netzwerk- und Kanalseiten
|
||||
- args: 'wall' - 1 oder 0, Begrenzung auf Wall-Posts oder Netzwerk-/Matrix-Posts (Standard)
|
||||
- fullprofile - wie das aktuelle Profil
|
||||
- categories - Kategorien-Filter (Channel-Seite)
|
||||
- tagcloud_wall - Tagcloud nur für Channelseite
|
||||
- args: 'limit' - Anzahl der Tags, die zurückgegeben werden sollen (Standardwert 50)
|
||||
- catcloud_wall - Tagcloud für die Kategorien der Kanalseite
|
||||
- args: 'limit' - Anzahl der zurückzugebenden Kategorien (Standardwert 50)
|
||||
- affinity - Affinitäts-Schieberegler für die Netzwerk-Seite - muss eingeloggt sein
|
||||
- settings_menu - Seitenleistenmenü für die Einstellungsseite, muss eingeloggt sein
|
||||
- mailmenu - Seitenleistenmenü für die Seite mit den privaten Nachrichten - muss eingeloggt sein
|
||||
- design_tools - Menü für Design-Tools für Seiten zur Erstellung von Webseiten, muss eingeloggt sein
|
||||
- findpeople - Werkzeuge, um andere Kanäle zu finden
|
||||
- photo_albums - Liste der Fotoalben des aktuellen Seitenbesitzers mit einem Auswahlmenü
|
||||
- vcard - Mini-Profil-Seitenleiste für die Person von Interesse (Seitenbesitzer, was auch immer)
|
||||
- dirsafemode - Werkzeug zur Verzeichnisauswahl - nur auf Verzeichnisseiten
|
||||
- dirsort - Werkzeug zur Verzeichnisauswahl - nur auf Verzeichnisseiten
|
||||
- dirtags - Verzeichnis-Werkzeug - nur auf Verzeichnisseiten
|
||||
- menu_preview - Vorschau eines Menüs - nur auf Menübearbeitungsseiten
|
||||
- chatroom_list - Liste der Chaträume für den Seitenbesitzer
|
||||
- bookmarkedchats - Liste der Chaträume mit Lesezeichen, die auf dieser Seite für den aktuellen Betrachter gesammelt wurden
|
||||
- suggestedchats - „interessante“ Chaträume für den aktuellen Betrachter ausgewählt
|
||||
- item - zeigt ein einzelnes Webpage-Element nach Mitte oder Seitentitel an
|
||||
- args:
|
||||
- channel_id - Kanal, dem der Inhalt gehört, Standard ist die profile_uid
|
||||
- mid - message_id der anzuzeigenden Webseite (muss eine Webseite sein, kein Konversationselement)
|
||||
- title - URL-Seitentitel der Webseite (muss entweder title oder mid enthalten)
|
||||
- photo - Anzeige eines einzelnen Fotos
|
||||
- args:
|
||||
- src - URL des Fotos, muss http oder https sein
|
||||
- zrl - zid-authentifizierter Link verwenden
|
||||
- style - CSS-Style-String
|
||||
- cover_photo - zeigt das Titelbild für den ausgewählten Kanal an
|
||||
- args:
|
||||
- channel_id - zu verwendender Kanal, Standard ist die profile_uid
|
||||
- style - CSS-Style-String (standardmäßig wird die Größe dynamisch an die Breite des Bereichs angepasst)
|
||||
|
||||
- photo_rand - zeigt ein zufälliges Foto aus einem Ihrer Fotoalben an. Fotoberechtigungen werden beachtet
|
||||
- args:
|
||||
- album - Name des Albums (sehr zu empfehlen, wenn Sie viele Fotos haben)
|
||||
- scale - typischerweise 0 (Originalgröße), 1 (1024px), 2, (640px) oder 3 (320px)
|
||||
- style - CSS-Style-String
|
||||
- channel_id - wenn nicht Ihre eigene
|
||||
- random_block - zeigt ein zufälliges Blockelement aus Ihrer Sammlung von Webpage Design Tools an. Erlaubnisse werden beachtet.
|
||||
- args:
|
||||
- contains - gibt nur Blöcke zurück, die den String contains im Blocknamen enthalten
|
||||
- channel_id - wenn nicht Ihre eigene
|
||||
- tasklist - liefert eine Aufgaben- oder To-Do-Liste für den aktuell eingeloggten Channel.
|
||||
- args:
|
||||
- all - zeigt erledigte Aufgaben an, wenn all ungleich Null ist.
|
||||
- forums - liefert eine Liste der verbundenen öffentlichen Foren mit ungesehenen Beiträgen für den aktuell eingeloggten Channel.
|
||||
- activity - liefert eine Liste der Autoren von ungelesenen Netzwerkinhalten für den aktuell eingeloggten Channel.
|
||||
- album - stellt ein Widget zur Verfügung, das ein komplettes Fotoalbum aus den Alben des Seitenbesitzers enthält; dies kann zu groß sein, um in einem Seitenleistenbereich dargestellt zu werden, und wird am besten als Widget für einen Inhaltsbereich implementiert.
|
||||
- args:
|
||||
- album - Name des Albums
|
||||
- title - optionaler Titel, wenn nicht vorhanden wird der Albumname verwendet
|
||||
|
||||
#### **Neue Widgets erstellen**
|
||||
|
||||
#### **Klassen-Widgets**
|
||||
|
||||
Um ein klassenbasiertes Widget namens 'slugfish' zu erstellen, erstellen Sie eine Datei mit folgendem Inhalt:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace Zotlabs\Widget;
|
||||
class Slugfish {
|
||||
|
||||
function widget($args) {
|
||||
|
||||
... der Widget-Code kommt hier hin.
|
||||
... Die Funktion gibt einen String zurück, der den HTML-Inhalt des Widgets darstellt.
|
||||
... $args ist ein benanntes Array, dem alle [var]-Variablen aus dem Layout-Editor übergeben werden
|
||||
... Zum Beispiel füllt [widget=slugfish][var=count]3[/var][/widget] $args mit
|
||||
... [ 'count' => 3 ]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
```
|
||||
|
||||
Die resultierende Datei kann in Zotlabs/Widgets/Slugfish.php abgelegt werden. Sie kann auch von einem Git-Repository mit util/add_widget_repo verlinkt werden.
|
||||
111
doc/de/adminmanual/Zot---A-High-Level-Overview.md
Normal file
111
doc/de/adminmanual/Zot---A-High-Level-Overview.md
Normal file
@@ -0,0 +1,111 @@
|
||||
### Nomad - Ein Überblick auf oberer Ebene
|
||||
|
||||
Hier ist eine allgemeine Beschreibung der Funktionsweise von Nomad.
|
||||
|
||||
In diesem Beispiel wird „Indigo“ eine öffentliche Nachricht von seiner Website „podunk.edu“ aus versenden. „Nickordo„ ist ein Empfänger auf einer anderen Website (“example.com").
|
||||
|
||||
Indigo stellt seine Nachricht zuerst auf podunk.edu ein. podunk.edu schaut nach, wer die Nachricht erhalten soll und findet Nickordo. Nickordo postet normalerweise von example.com aus, also fügen wir dieses Ziel zu unserer Liste der Empfänger hinzu. Wir können auch andere Ziele für Nickordo und alle anderen, die Indigos Beiträge verfolgen, hinzufügen.
|
||||
|
||||
In diesem Beispiel stellen wir fest, dass wir nur einen bekannten Empfänger an einem bekannten Ort haben.
|
||||
|
||||
Wir senden ein Paket an example.com:
|
||||
|
||||
|
||||
|
||||
{
|
||||
"type":"notify",
|
||||
"sender":{
|
||||
"guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA",
|
||||
"guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q",
|
||||
"url":"http:\/\/podunk.edu",
|
||||
"url_sig":"T8Bp7j5DHHhQDCFcAHXfuhUfGk2P3inPbImwaXXF1xJd3TGgluoXyyKDx6WDm07x0hqbupoAoZB1qBP3_WfvWiJVAK4N1FD77EOYttUEHZ7L43xy5PCpojJQmkppGbPJc2jnTIc_F1vvGvw5fv8gBWZvPqTdb6LWF6FLrzwesZpi7j2rsioZ3wyUkqb5TDZaNNeWQrIEYXrEnWkRI_qTSOzx0dRTsGO6SpU1fPWuOOYMZG8Nh18nay0kLpxReuHCiCdxjXRVvk5k9rkcMbDBJcBovhiSioPKv_yJxcZVBATw3z3TTE95kGi4wxCEenxwhSpvouwa5b0hT7NS4Ay70QaxoKiLb3ZjhZaUUn4igCyZM0h6fllR5I6J_sAQxiMYD0v5ouIlb0u8YVMni93j3zlqMWdDUZ4WgTI7NNbo8ug9NQDHd92TPmSE1TytPTgya3tsFMzwyq0LZ0b-g-zSXWIES__jKQ7vAtIs9EwlPxqJXEDDniZ2AJ6biXRYgE2Kd6W_nmI7w31igwQTms3ecXe5ENI3ckEPUAq__llNnND7mxp5ZrdXzd5HHU9slXwDShYcW3yDeQLEwAVomTGSFpBrCX8W77n9hF3JClkWaeS4QcZ3xUtsSS81yLrp__ifFfQqx9_Be89WVyIOoF4oydr08EkZ8zwlAsbZLG7eLXY"
|
||||
},
|
||||
"callback":"\/post",
|
||||
"version":1,
|
||||
"secret":"1eaa6613699be6ebb2adcefa5379c61a3678aa0df89025470fac871431b70467"
|
||||
}
|
||||
|
||||
In diesem Paket steht das Folgende:
|
||||
|
||||
Ich bin Indigo und hier ist der Beweis. Ich poste von podunk.edu und hier ist der Beweis. Ich habe ein Paket für Sie. Die Kontrollnummer lautet „1eaa6613....“.
|
||||
|
||||
Example.com nimmt dieses Paket an und sagt: „Moment mal - ich kenne Sie nicht. Ich möchte beweisen, wer du bist.“ Example.com stellt also eine Verbindung zu podunk.edu über eine „bekannte URL“ her, die wir für diesen Zweck verwenden, und sucht nach der oben genannten „guid“. Es sollte eine Reihe von Informationen zurückgeben, darunter auch einen öffentlichen Schlüssel. Example.com verwendet diesen Schlüssel, um die Signaturen in der Nachricht zu überprüfen und festzustellen, ob es tatsächlich eine Person namens Indigo bei podunk.edu gibt. Wir müssen dies nur einmal tun. (Beachten Sie, dass Indigo von jedem Ort aus posten kann. Wir müssen nur beweisen, dass es sich um Indigo handelt und dass Indigo beweisen kann, dass er von einem anderen Standort aus postet).
|
||||
|
||||
Dann trennt example.com die Verbindung und weist darauf hin, dass eine Nachricht auf podunk.edu wartet. Entweder sofort oder immer dann, wenn der Drang besteht (je nachdem, wie wichtig Indigo für jemanden auf dieser Website ist), „ruft“ example.com podunk.edu an. Die Nachricht lautet in etwa so:
|
||||
|
||||
|
||||
|
||||
{
|
||||
"type":"pickup",
|
||||
"url":"http:\/\/example.com",
|
||||
"callback_sig":"teE1_fLIqfyeCuZY4iS7sNU8jUlUuqYOYBiHLarkC99I9K-uSr8DAwVW8ZPZRK-uYdxRMuKFb6cumF_Gt9XjecCPBM8HkoXHOi_VselzJkxPwor4ZPtWYWWaFtRfcAm794LrWjdz62zdESTQd2JJIZWbrli1sUhK801BF3n0Ye6-X1MWhy9EUTVlNimOeRipcuD_srMhUcAXOEbLlrugZ8ovy2YBe6YOXkS8jj0RSFjsOduXAoVhQmNpcobSYsDvaQS3e3MvE6-oXE602zGQhuNLr7DIMt9PCdAeQo-ZM-DHlZGCkGk4O2oQFCXFzGPqLUMWDACGJfTfIWGoh_EJqT_SD5b_Yi_Wk9S1lj7vb-lmxe5JuIf7ezWzHoBT8vswnZxPYlidH2i9wapdzij9il_qqcCWWHIp7q_XkY_Zj52Z4r4gdmiqM-8y1c_1SDX7hrJFRwqL_PKFbEvyi5nMWTEzqp55Tay5Woiv19STK_H_8ufFfD9AOkYnk6rIOMsk9dn3a5tAFpDRyRndXkBWAXwiJjiND2zjue7BFu7Ty40THXcfYRh1a5XrAXcaGeYuagg-8J9tAufu9_LY3qGazFg8kRBVMOn4M8DRKSIhKj7z4MnbYL0s09gREojy4jqWO3VkaOjP2jUGzoPuUDLasudE1ehWFq0K_MTQNavgmp8",
|
||||
"callback":"http:\/\/example.com\/post",
|
||||
"secret":"1eaa6613699be6ebb2adcefa5379c61a3678aa0df89025470fac871431b70467",
|
||||
"secret_sig":"O7nB4_UJHBXi28Suwl9LBZF9hI_9KGVTgehnUlWF1oYMNRnBbVHB9lzUfAoalvp3STbU3xJbtD_S58tv6MfV7J5j2V_S1W5ex3dulmDGB8Pt_7Fe5mbEPmjQFcfv3Eg5dUjYIuDl0TDScfrHyImj7RZIWHbwd7wWVoMzzDa_o33klpYmKZCBvObCh55bRrlFkXZs_dRuOiPwkfX0C6_XES4OyOIYl45V30rdhmf-STrf4L9dKYy_axQ12RIwRcKychvVLwlUJn3bn9lgNXRRU_HTne-09OPcJbUOdcD3DkFoKOxMULBNKPHzsCau0ICYug7S0EP6LpCom_mW78s08LyVA1vYeFZjevBCiGecj57yIAQDYi6_rpWJfihYaWHRN0oqtScUR4Bdf0bQbEHxMs4zAtrOAxfyJCbi6U1pfnGgzXzB9ulOYGnVGNTF7Ey4K7FOZIBtk0ILY2JfvBUaVvVs8ttagOOHmhWhnbCvrnOFlkNdlce7zoJCSUJENUOCYmTRfwB_Jno5fAzRnrsYU3_Z-l1mzniU_OmUPz8mPEh7PwhkqAiVlyaM-q15gn7l2lAIDk9kp2X_iCme7v4V0ADN_DbpaI_0-6mPw5HLbKrCsA-sxlSMB4DO4lDCHYkauj0l25sbfroRWB_hax1O4Q0oWyOlVJLUqEC5nuUJCCE"
|
||||
}
|
||||
|
||||
Was diese Nachricht aussagt, ist: Hier ist example.com, ich habe einen Beweis, und ich bin hier, um ein Paket abzuholen. Hier ist die Sendungsverfolgungsnummer, und hier ist der Beweis, dass dies die Sendungsverfolgungsnummer ist, die Sie vermutlich an example.com gesendet haben.
|
||||
|
||||
Gut genug. Podunk.edu überprüft die Geschichte und tatsächlich, es ist example.com, und ja, da wartet ein Paket mit dieser Kontrollnummer. Hier ist das Paket...
|
||||
|
||||
|
||||
|
||||
{
|
||||
"success":1,
|
||||
"pickup":{
|
||||
"notify":{
|
||||
"type":"notify",
|
||||
"sender":{
|
||||
"guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA",
|
||||
"guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q",
|
||||
"url":"http:\/\/z.podunk.edu",
|
||||
"url_sig":"T8Bp7j5DHHhQDCFcAHXfuhUfGk2P3inPbImwaXXF1xJd3TGgluoXyyKDx6WDm07x0hqbupoAoZB1qBP3_WfvWiJVAK4N1FD77EOYttUEHZ7L43xy5PCpojJQmkppGbPJc2jnTIc_F1vvGvw5fv8gBWZvPqTdb6LWF6FLrzwesZpi7j2rsioZ3wyUkqb5TDZaNNeWQrIEYXrEnWkRI_qTSOzx0dRTsGO6SpU1fPWuOOYMZG8Nh18nay0kLpxReuHCiCdxjXRVvk5k9rkcMbDBJcBovhiSioPKv_yJxcZVBATw3z3TTE95kGi4wxCEenxwhSpvouwa5b0hT7NS4Ay70QaxoKiLb3ZjhZaUUn4igCyZM0h6fllR5I6J_sAQxiMYD0v5ouIlb0u8YVMni93j3zlqMWdDUZ4WgTI7NNbo8ug9NQDHd92TPmSE1TytPTgya3tsFMzwyq0LZ0b-g-zSXWIES__jKQ7vAtIs9EwlPxqJXEDDniZ2AJ6biXRYgE2Kd6W_nmI7w31igwQTms3ecXe5ENI3ckEPUAq__llNnND7mxp5ZrdXzd5HHU9slXwDShYcW3yDeQLEwAVomTGSFpBrCX8W77n9hF3JClkWaeS4QcZ3xUtsSS81yLrp__ifFfQqx9_Be89WVyIOoF4oydr08EkZ8zwlAsbZLG7eLXY"
|
||||
},
|
||||
"callback":"\/post",
|
||||
"version":1,
|
||||
"secret":"1eaa6613699be6ebb2adcefa5379c61a3678aa0df89025470fac871431b70467"
|
||||
},
|
||||
"message":{
|
||||
"message_id":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu",
|
||||
"message_top":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu",
|
||||
"message_parent":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu",
|
||||
"created":"2012-11-20 04:04:16",
|
||||
"edited":"2012-11-20 04:04:16",
|
||||
"title":"",
|
||||
"body":"Hi Nickordo",
|
||||
"app":"",
|
||||
"verb":"post",
|
||||
"object_type":"",
|
||||
"target_type":"",
|
||||
"permalink":"",
|
||||
"location":"",
|
||||
"longlat":"",
|
||||
"owner":{
|
||||
"name":"Indigo",
|
||||
"address":"indigo@podunk.edu",
|
||||
"url":"http:\/\/podunk.edu",
|
||||
"photo":{
|
||||
"mimetype":"image\/jpeg",
|
||||
"src":"http:\/\/podunk.edu\/photo\/profile\/m\/5"
|
||||
},
|
||||
"guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA",
|
||||
"guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q"
|
||||
},
|
||||
"author":{
|
||||
"name":"Indigo",
|
||||
"address":"indigo@podunk.edu",
|
||||
"url":"http:\/\/podunk.edu",
|
||||
"photo":{
|
||||
"mimetype":"image\/jpeg",
|
||||
"src":"http:\/\/podunk.edu\/photo\/profile\/m\/5"
|
||||
},
|
||||
"guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA",
|
||||
"guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Und das ist das Paket (die ursprüngliche Nachricht). Example.com wandelt diese in eine Form um, die von Nickordo eingesehen werden kann, und benachrichtigt Nickordo, dass es eine neue Nachricht gibt. Podunk.edu **könnte** feststellen, dass noch andere Pakete auf example.com warten. Wenn dies der Fall ist, kann es auch alle anderen wartenden Pakete zu diesem Zeitpunkt versenden. Jedes dieser Pakete ist mit der ursprünglichen Sendungsnummer versehen.
|
||||
13
doc/de/adminmanual/administration.md
Normal file
13
doc/de/adminmanual/administration.md
Normal file
@@ -0,0 +1,13 @@
|
||||
### Administration
|
||||
|
||||
#### Website-Verwaltung
|
||||
|
||||
Die Verwaltung der Website erfolgt in der Regel über die Verwaltungsseite, die sich unter /admin auf Ihrer Website befindet. Um auf diese Seite zugreifen zu können, müssen Sie über Verwaltungsrechte für den Server verfügen. Administrationsrechte werden dem ersten Konto gewährt, das sich auf Ihrer Website registriert, **vorausgesetzt,** die E-Mail-Adresse dieses Kontos stimmt genau mit der E-Mail-Adresse überein, die Sie bei der Einrichtung als E-Mail-Adresse des Administrators angegeben haben.
|
||||
|
||||

|
||||
|
||||
Es gibt mehrere Möglichkeiten, wie dies fehlschlagen und das System ohne ein Administratorkonto bleiben kann, z. B. wenn das erste Konto, das erstellt wurde, eine andere E-Mail-Adresse als die bei der Einrichtung angegebene Administrator-E-Mail-Adresse angegeben hat.
|
||||
|
||||
Aus Sicherheitsgründen gibt es auf dem System keine Webseite oder Schnittstelle, die Ihnen Administratorrechte verleiht. Wenn Sie eine Situation korrigieren müssen, in der ein System kein Administratorkonto hat, **muss** dies durch Bearbeiten der Kontotabelle in der Datenbank geschehen. Es gibt keine andere Möglichkeit. Dazu müssen Sie den Eintrag in der Kontotabelle finden, der zu dem gewünschten Administrator gehört, und „account_roles“ für diesen Eintrag auf 4096 setzen. Anschließend können Sie die Administratorseite über das Profilmenü Ihres Systems oder direkt über /admin aufrufen.
|
||||
|
||||
Ein Hub kann mehrere Administratoren haben und die Anzahl der Administratoren ist nicht begrenzt. Wiederholen Sie den obigen Vorgang für jedes Konto, das Sie mit Administrationsrechten ausstatten möchten.
|
||||
326
doc/de/adminmanual/advanced_configurations.md
Normal file
326
doc/de/adminmanual/advanced_configurations.md
Normal file
@@ -0,0 +1,326 @@
|
||||
### Erweiterte Konfigurationen für Administratoren
|
||||
|
||||
*Dieses Dokument setzt voraus, dass Sie ein Administrator sind.*
|
||||
|
||||
Hubzilla enthält viele Konfigurationsoptionen, die im Hauptverwaltungsbereich verborgen sind. Im Allgemeinen handelt es sich dabei um Optionen, die als zu nischenartig, fortgeschritten oder verwirrend angesehen werden.
|
||||
|
||||
Diese Einstellungen können über die Shell vom Webverzeichnis der obersten Ebene aus mit folgender Syntax geändert werden
|
||||
|
||||
`util/config cat key value`
|
||||
für eine Website-Konfiguration, oder
|
||||
|
||||
`util/pconfig channel_id cat key value`
|
||||
für eine Mitgliedskonfiguration.
|
||||
|
||||
Für eine Site-Konfiguration ist eine weitere Möglichkeit, eine Zeile in .htconfig.php einzufügen, mit der Syntax:
|
||||
`App::$config['cat']['Schlüssel'] = 'Wert';`
|
||||
|
||||
|
||||
|
||||
#### Mitgliederkonfiguration (pconfig)
|
||||
|
||||
- system.always_my_theme
|
||||
|
||||
Verwende immer dein eigenes Theme, wenn du Kanäle im selben Hub anschaust. Dies führt zu einigen recht einfallsreichen Problemen, wenn Kanäle mit themenabhängigen Comanche angezeigt werden.
|
||||
|
||||
- system.blocked
|
||||
|
||||
Ein Array von Xchans, die von diesem Channel blockiert werden. Technisch gesehen ist dies eine versteckte Konfiguration und gehört hierher, aber Addons (insbesondere Superblock) haben dies in der Benutzeroberfläche verfügbar gemacht.
|
||||
|
||||
- system.default_cipher
|
||||
|
||||
Setzt den Standardchiffre, der für E2EE-Elemente verwendet wird.
|
||||
|
||||
- system.display_friend_count
|
||||
|
||||
Legt die Anzahl der Verbindungen fest, die im Widget des Verbindungsprofils angezeigt werden sollen.
|
||||
|
||||
- system.do_not_track
|
||||
|
||||
Wie der Browser-Header. Dies wird viele identitätsbasierte Funktionen unterbrechen. Sie sollten wirklich nur Berechtigungen setzen, die Sinn machen.
|
||||
|
||||
- system.forcepublicuploads
|
||||
|
||||
Erzwingt, dass hochgeladene Fotos öffentlich sind, wenn sie als Wandelemente hochgeladen werden. Es ist viel sinnvoller, die Berechtigungen von vornherein richtig zu setzen. Tun Sie das stattdessen.
|
||||
|
||||
- system.network_page_default
|
||||
|
||||
Legt die Standardparameter für die Anzeige der Netzwerkseite fest. Dies sollte den gleichen Querystring enthalten wie die manuelle Filterung.
|
||||
|
||||
- system.paranoia
|
||||
|
||||
Legt die Sicherheitsstufe der IP-Überprüfung fest. Wenn sich die IP-Adresse einer angemeldeten Sitzung ändert, wird diese Stufe angewendet, um festzustellen, ob das Konto als Sicherheitsverletzung abgemeldet werden sollte. Die Optionen sind: 0 - keine IP-Überprüfung 1 - 3 Oktette prüfen 2 - 2 Oktette prüfen 3 - Prüfung auf alle Unterschiede
|
||||
|
||||
- system.prevent_tag_hijacking
|
||||
|
||||
Verhindert, dass fremde Netzwerke Hashtags in Ihren Beiträgen klauen und sie auf ihre eigenen Ressourcen leiten.
|
||||
|
||||
- system.startpage
|
||||
|
||||
Eine weitere dieser technisch versteckten Konfigurationen, die von Addons zur Verfügung gestellt werden. Legt die Standardseite fest, die beim Einloggen angezeigt wird. Diese wird der Benutzeroberfläche durch das startpage-Addon zur Verfügung gestellt.
|
||||
|
||||
- system.taganyone
|
||||
|
||||
Erfordert, dass die gleichnamige Konfiguration aktiviert ist. Erlaubt das @mention tagging von jedem, egal ob man verbunden ist oder nicht. Dies skaliert nicht.
|
||||
|
||||
- system.anonymous_kommentare
|
||||
|
||||
Standardmäßig oder wenn auf 1 gesetzt, können benutzerdefinierte Berechtigungen gesetzt werden, um anonyme (moderierte) Kommentare wie bei WordPress zu erlauben, die vom Channel-Besitzer moderiert werden. Ist der Wert auf 0 gesetzt, kann kein Mitglied Ihrer Website dies auswählen oder aktivieren.
|
||||
|
||||
- system.user_scalable
|
||||
|
||||
Bestimmt, ob die App auf Touchscreens skalierbar ist. Standardmäßig auf on, zum Deaktivieren auf zero setzen - real zero, nicht nur false.
|
||||
|
||||
#### Konfiguration der Website
|
||||
|
||||
- randprofile.check
|
||||
|
||||
Bei der Anforderung eines Zufallsprofils zuerst prüfen, ob es tatsächlich existiert
|
||||
|
||||
- randprofile.retry
|
||||
|
||||
Anzahl der Versuche, ein zufälliges Profil zu erhalten
|
||||
|
||||
- system.admin_email
|
||||
|
||||
Gibt die E-Mail-Adresse des Administrators für diese Site an. Diese wird bei der Installation festgelegt.
|
||||
|
||||
- system.authlog
|
||||
|
||||
Logdatei, die für die Protokollierung von Authentifizierungsfehlern verwendet wird. Wird verwendet, um eine Verbindung zu serverseitiger Software wie fail2ban herzustellen. Auth-Fehler werden auch in den Hauptprotokollen protokolliert.
|
||||
|
||||
- system.auto_channel_create
|
||||
|
||||
Fügt die notwendigen Formularelemente hinzu, um den ersten Kanal auf der Kontoregistrierungsseite zu erstellen, und erstellt ihn (möglicherweise nach einer E-Mail-Validierung oder der Genehmigung des Administrators). Dies schließt die Möglichkeit aus, einen Channel von einer anderen Website als ersten auf dieser Website für ein neues Konto erstellten Channel zu importieren. Verwendung mit system.default_permissions_role zur Rationalisierung der Registrierung.
|
||||
|
||||
- system.auto_follow
|
||||
|
||||
Der erste Channel eines Accounts folgt automatisch den hier aufgelisteten Channels - kommagetrennte Liste von Webbies (member@hub Adressen).
|
||||
|
||||
- system.blacklisted_sites
|
||||
|
||||
Ein Array spezifischer Hubs, die von diesem Hub komplett blockiert werden sollen.
|
||||
|
||||
- system.block_public_search
|
||||
|
||||
Ähnlich wie block_public, mit dem Unterschied, dass nur der öffentliche Zugang zu den Suchfunktionen blockiert wird. Nützlich für Seiten, die öffentlich sein wollen, aber von Suchmaschinen überrannt werden.
|
||||
|
||||
- system.cron_hour
|
||||
|
||||
Geben Sie eine Stunde an, in der cron_daily ausgeführt werden soll. Standardmäßig, ohne Konfiguration, wird dies um Mitternacht UTC ausgeführt.
|
||||
|
||||
- system.default_permissions_role
|
||||
|
||||
Wenn dieser Wert auf einen gültigen Namen für eine Berechtigungsrolle gesetzt ist, wird diese Rolle für den ersten Channel verwendet, der von einem neuen Konto erstellt wird, und es wird nicht nach dem „Channel-Typ“ im Formular zur Channel-Erstellung gefragt. Beispiele für gültige Namen sind: 'social', 'social_restricted', 'social_private', 'forum', 'forum_restricted' und 'forum_private'. Lesen Sie [hier](https://hub.hubzilla.hu/help/roles) mehr über Berechtigungsrollen.
|
||||
|
||||
- system.default_profile_photo
|
||||
|
||||
Legt das Profilfoto fest, mit dem neue Channels beginnen. Dies sollte den Namen eines Verzeichnisses enthalten, das sich unter images/default_profile_photos/ befindet, oder es sollte nicht gesetzt werden. Wenn es nicht gesetzt ist, wird 'rainbow_man' angenommen.
|
||||
|
||||
- system.directorytags
|
||||
|
||||
Legt die Anzahl der Schlüsselwort-Tags fest, die auf der Verzeichnisseite angezeigt werden. Die Voreinstellung ist 50, wenn sie nicht auf eine positive ganze Zahl gesetzt wird.
|
||||
|
||||
- system.disable_directory_keywords
|
||||
|
||||
Wenn '1', werden keine Verzeichnisschlüsselwörter angezeigt. Wenn der Hub ein Verzeichnisserver ist, verhindern Sie die Rückgabe von Schlüsselwörtern an alle Verzeichnis-Clients. Bitte setzen Sie dies nicht für Verzeichnisserver im Bereich RED_GLOBAL.
|
||||
|
||||
- system.disable_discover_tab
|
||||
|
||||
Hiermit können Sie die Fähigkeit, öffentliche Inhalte von externen Sites zu entdecken, vollständig deaktivieren.
|
||||
|
||||
- system.disable_dreport
|
||||
|
||||
Wenn '1', werden keine Zustellungsberichte gespeichert oder verlinkt.
|
||||
|
||||
- system.dlogfile
|
||||
|
||||
Logdatei, die für die Protokollierung von Entwicklungsfehlern verwendet wird. Genau dasselbe wie logger sonst. Dies ist keine Magie und erfordert Ihre eigenen Logging-Anweisungen. Entwickler-Tool.
|
||||
|
||||
- system.email_notify_icon_url
|
||||
|
||||
URL des Bildes (32x32), das in E-Mail-Benachrichtigungen (HTML-Bodies) angezeigt werden soll.
|
||||
|
||||
- system.expire_delivery_reports
|
||||
|
||||
Verfallsdatum in Tagen für Zustellungsberichte - Standardwert 10
|
||||
|
||||
- system.expire_limit
|
||||
|
||||
Nicht mehr als diese Anzahl von Beiträgen pro Kanal pro Ablauflauf ablaufen lassen, um den Speicher nicht zu erschöpfen. Voreinstellung 5000.
|
||||
|
||||
- system.photo_storage_type
|
||||
|
||||
Wenn '1', wird das Dateisystem anstelle der SQL-Datenbank zum Speichern der Thumbnails verwendet. Voreinstellung ist '0'. Eingeführt in 4.2
|
||||
|
||||
- system.hidden_version_siteinfo
|
||||
|
||||
Wenn 'true', wird die Softwareversion nicht auf den Seiten von siteinfo angezeigt (system.hide_version verbirgt die Version auch auf diesen Seiten, diese Einstellung verbirgt *nur* die Version auf den Seiten von siteinfo).
|
||||
|
||||
- system.hide_help
|
||||
|
||||
Link zur Hilfedokumentation nicht in der Navigationsleiste anzeigen
|
||||
|
||||
- system.hide_in_statistiken
|
||||
|
||||
Weist die roten Statistikserver an, diesen Hub in Hublisten komplett auszublenden.
|
||||
|
||||
- system.hide_version
|
||||
|
||||
Wenn true, wird die Softwareversion auf Webseiten und Tools nicht angezeigt. (*) Muss in .htconfig.php eingestellt werden.
|
||||
|
||||
- system.ignore_imagick
|
||||
|
||||
Ignoriert imagick und verwendet GD, auch wenn imagick auf dem Server installiert ist. Verhindert einige Probleme mit PNG-Dateien in älteren Versionen von imagick.
|
||||
|
||||
- system.max_daily_registrations
|
||||
|
||||
Legt die maximale Anzahl der an einem Tag erlaubten Neuanmeldungen fest. Nützlich, um eine Überzeichnung zu verhindern, wenn das Projekt in der Öffentlichkeit bekannt gemacht wird.
|
||||
|
||||
- system.max_import_size
|
||||
|
||||
Falls konfiguriert, die maximale Länge einer importierten Textnachricht. Diese wird normalerweise auf 200 KByte oder mehr belassen, um private Friendica-Fotos, die eingebettet sind, unterzubringen.
|
||||
|
||||
- system.max_tagged_forums
|
||||
|
||||
Spam-Schutz. Begrenzt die Anzahl der getaggten Foren, die in jedem Beitrag erkannt werden. Standard ist 2. Nur die ersten 'n' Tags werden als Foren zugestellt, die anderen verursachen keine Zustellung.
|
||||
|
||||
- system.minimum_feedcheck_minutes
|
||||
|
||||
Das minimale Intervall zwischen der Abfrage von RSS-Feeds. Wenn dieses Intervall kleiner als das Cron-Intervall ist, werden die Feeds bei jedem Cronjob abgefragt. Der Standardwert ist 60, wenn er nicht festgelegt wurde. Die Site-Einstellung kann auch für jeden einzelnen Kanal durch eine Serviceklassen-Einstellung mit dem treffenden Namen „minimum_feedcheck_minutes“ außer Kraft gesetzt werden.
|
||||
|
||||
- system.no_age_restriction
|
||||
|
||||
Beschränken Sie die Registrierung nicht auf Personen über 13 Jahren. In vielen Ländern ist es gesetzlich vorgeschrieben, dass das Alter angegeben werden muss und dass alle persönlichen Daten von Minderjährigen gesperrt werden müssen.
|
||||
|
||||
- system.object_cache_days
|
||||
|
||||
Legt fest, wie lange zwischengespeicherte eingebettete Inhalte ohne erneutes Abrufen verwendet werden können. Die Voreinstellung ist 30 Tage.
|
||||
|
||||
- system.openssl_conf_file
|
||||
|
||||
Geben Sie eine Datei an, die die OpenSSL-Konfiguration enthält. Wird in einigen Windows-Installationen benötigt, um die openssl-Konfigurationsdatei auf dem System zu finden. Lesen Sie zuerst den Code. Wenn Sie den Code nicht lesen können, spielen Sie nicht mit ihm.
|
||||
|
||||
- system.openssl_encrypt
|
||||
|
||||
Verschlüsselungs-Engine von openssl verwenden, Standard ist false (verwendet mcrypt für AES-Verschlüsselung)
|
||||
|
||||
- system.optimize_items
|
||||
|
||||
Führt optimise_table während einiger Aufgaben aus, um Ihre Datenbank sauber und defragmentiert zu halten. Dies geht zu Lasten der Leistung, während die Operationen laufen, sorgt aber auch dafür, dass die Dinge etwas schneller laufen, wenn sie nicht laufen. Es gibt auch CLI-Hilfsprogramme zur Durchführung dieser Operation, die Sie vielleicht bevorzugen, besonders wenn Sie eine große Site haben.
|
||||
|
||||
- system.override_poll_lockfile
|
||||
|
||||
Ignoriert die Sperrdatei im Poller-Prozess, damit mehr als ein Prozess gleichzeitig laufen kann.
|
||||
|
||||
- system.paranoia
|
||||
|
||||
Wie pconfig, aber auf einer site-weiten Basis. Kann durch Mitgliedereinstellungen überschrieben werden.
|
||||
|
||||
- system.pin_types
|
||||
|
||||
Array der zulässigen Elementtypen für die Anheftung. Die Standardwerte hängen vom Modul ab, können aber hier geändert werden.
|
||||
|
||||
- system.photo_cache_time
|
||||
|
||||
Wie lange die Fotos zwischengespeichert werden sollen, in Sekunden. Standardwert ist 86400 (1 Tag). Eine längere Zeit erhöht die Leistung, bedeutet aber auch, dass es länger dauert, bis geänderte Berechtigungen gelten.
|
||||
|
||||
- system.plattform_name
|
||||
|
||||
Was als Plattformname auf Webseiten und in Statistiken angezeigt werden soll. (*) Muss in .htconfig.php eingestellt werden.
|
||||
|
||||
- system.rating_enabled
|
||||
|
||||
Verteilte Reputationsberichte und Datenerfassung. Diese Funktion wird derzeit überarbeitet.
|
||||
|
||||
- system.poke_basic
|
||||
|
||||
Reduziert die Anzahl der poke-Verben auf genau 1 („poke“). Deaktivieren Sie andere Verben.
|
||||
|
||||
- system.proc_run_use_exec
|
||||
|
||||
Wenn 1, wird der Systemaufruf exec in proc_run verwendet, um Hintergrundaufgaben auszuführen. Standardmäßig verwenden wir proc_open und proc_close. Auf einigen (derzeit seltenen) Systemen funktioniert dies nicht gut.
|
||||
|
||||
- system.projecthome
|
||||
|
||||
Zeigt die Projektseite auf Ihrer Homepage für abgemeldete Betrachter an.
|
||||
|
||||
- system.projekthome
|
||||
|
||||
Legt die Projekthomepage als Startseite des Hubs fest. (Veraltet)
|
||||
|
||||
- system.pubstream_bestellung
|
||||
|
||||
Legt die Pubstream-Reihenfolge fest. Mögliche Werte 'commented' (Standard), 'created' und 'edited'.
|
||||
|
||||
- system.register_link
|
||||
|
||||
Pfad, auf den der „register“-Link im Anmeldeformular verweisen soll. Bei geschlossenen Sites wird dies auf 'pubsites' verweisen. Bei offenen Sites wird er normalerweise auf 'register' umgeleitet, aber Sie können dies auf eine benutzerdefinierte Site-Seite ändern, die Abonnements oder ähnliches anbietet.
|
||||
|
||||
- system.reserved_channels
|
||||
|
||||
Erlaube den Mitgliedern nicht, Kanäle mit dieser durch Kommata getrennten Liste von Namen (keine Leerzeichen) zu registrieren.
|
||||
|
||||
- system.sellpage
|
||||
|
||||
Eine URL, die in der Liste der öffentlichen Sites angezeigt wird, um Ihren Hub zu verkaufen - Serviceklassen anzeigen, usw.
|
||||
|
||||
- system.startpage
|
||||
|
||||
Legt die Standardseite fest, die nach einer Anmeldung für alle Channels auf dieser Website angezeigt wird. Kann durch Benutzereinstellungen überschrieben werden.
|
||||
|
||||
- system.sys_expire_days
|
||||
|
||||
Wie viele Tage sollen entdeckte öffentliche Inhalte von anderen Websites aufbewahrt werden?
|
||||
|
||||
- system.taganyone
|
||||
|
||||
Erlaubt das @mention-Tagging von jedem, egal ob Sie verbunden sind oder nicht.
|
||||
|
||||
- system.tempdir
|
||||
|
||||
Ort, an dem temporäre Dateien gespeichert werden (derzeit unbenutzt), Standard ist in der PHP-Konfiguration definiert.
|
||||
|
||||
- system.tos_url
|
||||
|
||||
Setzt einen alternativen Link für den ToS-Speicherort.
|
||||
|
||||
- system.transport_security_header
|
||||
|
||||
wenn ungleich Null und SSL verwendet wird, wird ein strict-transport-security-Header auf den Webseiten eingefügt
|
||||
|
||||
- system.uploaddir
|
||||
|
||||
Speicherort für das Hochladen von Dateien (Standard ist system.tempdir, derzeit nur vom js_upload-Plugin verwendet)
|
||||
|
||||
- system.workflow_channel_next
|
||||
|
||||
Die Seite, zu der neue Mitglieder unmittelbar nach der Erstellung eines Channels weitergeleitet werden sollen.
|
||||
|
||||
- system.arbeitsablauf_register_next
|
||||
|
||||
Die Seite, auf die Mitglieder direkt nach dem Erstellen eines Kontos geleitet werden (nur wenn auto_channel_create oder UNO aktiviert ist).
|
||||
|
||||
#### Verzeichnis-Konfiguration
|
||||
|
||||
##### Standardwerte für die Verzeichnissuche
|
||||
|
||||
- directory.globaldir
|
||||
|
||||
0 oder 1. Standardwert 0. Wenn Sie das Verzeichnis auf einer Site besuchen, sehen Sie standardmäßig nur die Mitglieder dieser Site. Man muss einen zusätzlichen Schritt machen, um die Leute im Rest des Netzwerks zu sehen; und indem man das tut, gibt es eine klare Abgrenzung, dass diese Leute *nicht* Mitglieder dieser Site sind, sondern eines größeren Netzwerks.
|
||||
|
||||
- directory.pubforums
|
||||
|
||||
0 oder 1. Öffentliche Foren *sollten* standardmäßig 0 sein.
|
||||
|
||||
- directory.safemode
|
||||
|
||||
0 oder 1.
|
||||
|
||||
##### Konfiguration des Verzeichnisservers
|
||||
|
||||
- system.directory_mode
|
||||
- system.directory_primary
|
||||
- system.directory_realm
|
||||
- system.verzeichnis_server
|
||||
- system.realm_token
|
||||
26
doc/de/adminmanual/automated_installation.md
Normal file
26
doc/de/adminmanual/automated_installation.md
Normal file
@@ -0,0 +1,26 @@
|
||||
### Automatisierte Installation über das Shell-Skript .homeinstall
|
||||
|
||||
Es gibt ein Shell-Skript in (`.homeinstall/hubzilla-setup.sh`), das Hubzilla und seine Abhängigkeiten auf einer frischen Installation von Debian stable installiert. Es sollte auf ähnlichen Linux-Systemen funktionieren, aber Ihre Ergebnisse können variieren.
|
||||
|
||||
#### Anforderungen
|
||||
|
||||
Das Installationsskript wurde ursprünglich für einen kleinen Hardwareserver hinter Ihrem Heimrouter entwickelt. Es wurde jedoch auf mehreren Systemen mit Debian 9 getestet:
|
||||
|
||||
- Home-PC (Debian-9.2-amd64) und Rapberry-Pi 3 (Rasbian = Debian 9.3)
|
||||
- Internetanschluss und Router zu Hause
|
||||
- Mini-PC / Raspi an den Router angeschlossen
|
||||
- USB-Laufwerk für Backups
|
||||
- Frische Installation von Debian auf Ihrem Mini-PC
|
||||
- Router mit offenen Ports 80 und 443 für Ihr Debian
|
||||
|
||||
#### Überblick über die Installationsschritte
|
||||
|
||||
1. `apt-get install git`
|
||||
2. `mkdir -p /var/www/html`
|
||||
3. `cd /var/www/html`
|
||||
4. `git clone https://framagit.org/hubzilla/core.git .`
|
||||
5. `nano .homeeinstall/hubzilla-config.txt`
|
||||
6. `cd .homeeinstall/`
|
||||
7. `./hubzilla-setup.sh`
|
||||
8. `service apache2 neu laden`
|
||||
9. Öffnen Sie Ihre Domain mit einem Browser und gehen Sie durch die anfängliche Konfiguration von Hubzilla.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user