mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-22 09:17:57 -04:00
Compare commits
737 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1def0c03a | ||
|
|
b8a5ebe0f7 | ||
|
|
24a9ad6260 | ||
|
|
88577e1e97 | ||
|
|
38225aabc9 | ||
|
|
3653ae1af0 | ||
|
|
f2aa42f18a | ||
|
|
aa5bd9bbfc | ||
|
|
42f75842c6 | ||
|
|
73fafd9f2b | ||
|
|
13c51e519d | ||
|
|
ef05cecaeb | ||
|
|
5b6d70fd60 | ||
|
|
cfb8bf3ab9 | ||
|
|
3cf7e09609 | ||
|
|
a127f76bad | ||
|
|
d11b05de71 | ||
|
|
a03b440139 | ||
|
|
2865dc45eb | ||
|
|
923e80d143 | ||
|
|
ba96b2ce85 | ||
|
|
d9f467f215 | ||
|
|
23a8c2f0a8 | ||
|
|
76856188e1 | ||
|
|
f3d8838256 | ||
|
|
2871ef2897 | ||
|
|
aa7358c837 | ||
|
|
57b553a79f | ||
|
|
f08498440a | ||
|
|
e9c07c554a | ||
|
|
a570ef4691 | ||
|
|
7cf7aa397e | ||
|
|
8ba378bc6f | ||
|
|
03af9d415f | ||
|
|
e5acf404ab | ||
|
|
2e89cfe5ed | ||
|
|
21951ec5ee | ||
|
|
10786336c5 | ||
|
|
9e33fa8ee2 | ||
|
|
1658244b09 | ||
|
|
3c60e33d74 | ||
|
|
5fb28cb51c | ||
|
|
1677c664f0 | ||
|
|
d35a79515f | ||
|
|
872fced729 | ||
|
|
4ae65a63c6 | ||
|
|
acc43bbbad | ||
|
|
947d827431 | ||
|
|
339f787b92 | ||
|
|
c71a6dbbd2 | ||
|
|
cd5815dcdc | ||
|
|
19c478421d | ||
|
|
a5f311665c | ||
|
|
d8c14eec58 | ||
|
|
4798fa79c3 | ||
|
|
b50aa43542 | ||
|
|
6bf1b15666 | ||
|
|
9d4f2c7817 | ||
|
|
040b52a1d5 | ||
|
|
c8c9e4a901 | ||
|
|
b4f6241357 | ||
|
|
4ba414fb8d | ||
|
|
33718ff16f | ||
|
|
19437f45ef | ||
|
|
7a7ff97e63 | ||
|
|
ef7cedca2d | ||
|
|
cbb2cabd74 | ||
|
|
f7cc249b50 | ||
|
|
9530b5b313 | ||
|
|
f91409a9ec | ||
|
|
4330e0bb94 | ||
|
|
6ad561dc4c | ||
|
|
70c7817a5c | ||
|
|
cc9237c7ce | ||
|
|
e75e8ed8f1 | ||
|
|
2e85852a9c | ||
|
|
c49a646bef | ||
|
|
c130c3ee45 | ||
|
|
c96fe501ef | ||
|
|
2f0f7b9df6 | ||
|
|
9fec396fa2 | ||
|
|
bf774caf0e | ||
|
|
f08b0edad2 | ||
|
|
63e41c233f | ||
|
|
48433c9479 | ||
|
|
4691bd37c9 | ||
|
|
d24a3a2713 | ||
|
|
57af09ad47 | ||
|
|
c5fc4827c8 | ||
|
|
3c89c7d4f4 | ||
|
|
2a3dc6cc50 | ||
|
|
c748d3f0f8 | ||
|
|
9b2ea44000 | ||
|
|
83f6846143 | ||
|
|
3b2311f356 | ||
|
|
ea0229dcfc | ||
|
|
3cdfa94c29 | ||
|
|
2fd5762125 | ||
|
|
52ecdb007f | ||
|
|
9b8fed738b | ||
|
|
ee3fafc9fb | ||
|
|
47867a0993 | ||
|
|
a2ba81afe1 | ||
|
|
a15254a1e2 | ||
|
|
1a68dbccf1 | ||
|
|
fc87ef282e | ||
|
|
ab0e5e3eee | ||
|
|
356b6127d3 | ||
|
|
87c62db41e | ||
|
|
0d3855cd63 | ||
|
|
ffce0a705b | ||
|
|
49e65902d7 | ||
|
|
2e1fd79c7a | ||
|
|
0c577b5fd0 | ||
|
|
3178a96a89 | ||
|
|
c1cec623bb | ||
|
|
d3cc098070 | ||
|
|
69e7812646 | ||
|
|
d39320475c | ||
|
|
0faf47b3ca | ||
|
|
660ff3da7b | ||
|
|
7ec8a2267a | ||
|
|
4a35764e13 | ||
|
|
3a50b185ce | ||
|
|
57e2904cc0 | ||
|
|
77866625cc | ||
|
|
b49c844a23 | ||
|
|
f6275fdb79 | ||
|
|
2c55ee5a73 | ||
|
|
548b0c4931 | ||
|
|
8c61f89a14 | ||
|
|
7cc0cb78a0 | ||
|
|
6aa945cde1 | ||
|
|
375b3f3f67 | ||
|
|
b68b5a60c5 | ||
|
|
f4c29d13f4 | ||
|
|
121fb74c6c | ||
|
|
4a098cbeaf | ||
|
|
6123fd2be8 | ||
|
|
176a7cb9b5 | ||
|
|
a7e734b700 | ||
|
|
b31123ae2f | ||
|
|
330c8ca890 | ||
|
|
e645ea3bf0 | ||
|
|
50f439ae8e | ||
|
|
3a102d9dc3 | ||
|
|
bb4c08caf0 | ||
|
|
f8795288a1 | ||
|
|
107b8e67d2 | ||
|
|
5a36a37b9f | ||
|
|
0910ae0e52 | ||
|
|
c6c5a8b5e0 | ||
|
|
da2c57c432 | ||
|
|
e7523e7fc5 | ||
|
|
e52d3639de | ||
|
|
1a27edf6dd | ||
|
|
9750543157 | ||
|
|
95dab5c764 | ||
|
|
619df9ca22 | ||
|
|
5442bac707 | ||
|
|
99688cdde5 | ||
|
|
6b7478c5a5 | ||
|
|
644e3b790c | ||
|
|
c064cfde91 | ||
|
|
2826d030f4 | ||
|
|
1ab1da5816 | ||
|
|
05800a5ff3 | ||
|
|
120292bd6c | ||
|
|
aaa863cda7 | ||
|
|
3c722f9aa7 | ||
|
|
14f28907bc | ||
|
|
185f53d298 | ||
|
|
3ae42d471a | ||
|
|
0a817f952e | ||
|
|
bc7f8b15a8 | ||
|
|
02111ad649 | ||
|
|
6f00964d47 | ||
|
|
eafa1d56c3 | ||
|
|
44a0311798 | ||
|
|
2ac06fef9a | ||
|
|
5b6a38aa2d | ||
|
|
37b9919905 | ||
|
|
283c018d07 | ||
|
|
51c79aecac | ||
|
|
9343f00918 | ||
|
|
962b4e5b4c | ||
|
|
eeef6cfd00 | ||
|
|
96c7912fa6 | ||
|
|
91f1f8ed7c | ||
|
|
3f7ed72ece | ||
|
|
3385c694aa | ||
|
|
a922f5ca6c | ||
|
|
88977a406c | ||
|
|
e98f019b16 | ||
|
|
50f5fcb16b | ||
|
|
bf35a661bf | ||
|
|
ecc94cdecd | ||
|
|
e79a70d2b1 | ||
|
|
6916a825ee | ||
|
|
b5a798f068 | ||
|
|
e5c54fadea | ||
|
|
f2217e9016 | ||
|
|
4d6bebb846 | ||
|
|
2e9b1d25e1 | ||
|
|
8604ba016e | ||
|
|
cc35afa4c9 | ||
|
|
f01c5ad0c1 | ||
|
|
7b6a8fdba1 | ||
|
|
2c9f184a09 | ||
|
|
6f158f37c9 | ||
|
|
f88d2ba0c4 | ||
|
|
170f157aae | ||
|
|
82817b4532 | ||
|
|
3eeaca4aab | ||
|
|
a3dd4a4d3d | ||
|
|
c383e6af80 | ||
|
|
517e14cc38 | ||
|
|
eb3dfb2488 | ||
|
|
70e8648d91 | ||
|
|
ae8e9bc353 | ||
|
|
88227b9155 | ||
|
|
ae77ab7f20 | ||
|
|
308380fe52 | ||
|
|
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 | ||
|
|
059113d2a8 | ||
|
|
f60dff788e |
@@ -34,14 +34,14 @@ if you look for more choices. The main differences are:
|
||||
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
|
||||
|
||||
@@ -80,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,...
|
||||
@@ -99,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
|
||||
@@ -149,5 +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!
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -307,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
|
||||
}
|
||||
@@ -386,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
|
||||
@@ -441,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
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
stages:
|
||||
- pretest
|
||||
- test
|
||||
- deploy
|
||||
|
||||
@@ -25,23 +26,6 @@ variables:
|
||||
POSTGRES_USER: ci-user
|
||||
POSTGRES_PASSWORD: ci-pass
|
||||
|
||||
|
||||
before_script:
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- apt-get update
|
||||
- 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-configure gd --with-jpeg=/usr/include/
|
||||
- docker-php-ext-install gd bcmath intl pdo_mysql pdo_pgsql zip
|
||||
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php ./composer.phar install --no-progress
|
||||
# php.ini settings
|
||||
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
|
||||
|
||||
# hidden job definition with template for MySQL/MariaDB
|
||||
.job_template_mysql: &job_definition_mysql
|
||||
stage: test
|
||||
@@ -53,13 +37,13 @@ before_script:
|
||||
HZ_TEST_DB_DATABASE: $MYSQL_DATABASE
|
||||
script:
|
||||
# Import hubzilla's DB schema
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$MYSQL_DATABASE"
|
||||
# Show databases and relations/tables of hubzilla's database
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$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+\%/'
|
||||
|
||||
@@ -84,7 +68,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+\%/'
|
||||
|
||||
@@ -100,29 +84,55 @@ before_script:
|
||||
paths:
|
||||
- tests/results/
|
||||
|
||||
default:
|
||||
image: php:8.2
|
||||
before_script:
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- apt-get update
|
||||
- apt-get install -yqq libicu-dev libjpeg-dev libpng-dev libpq-dev libyaml-dev libgmp-dev libzip-dev mariadb-client postgresql-client unzip zip
|
||||
- pecl install xdebug yaml
|
||||
- docker-php-ext-enable xdebug yaml
|
||||
- docker-php-ext-configure gd --with-jpeg=/usr/include/
|
||||
- docker-php-ext-install gd gmp intl pdo_mysql pdo_pgsql zip exif
|
||||
|
||||
# PHP8.1 with MySQL 8.0
|
||||
php8.1_mysql8.0.22:
|
||||
image: php:8.1
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php ./composer.phar install --no-progress
|
||||
# php.ini settings
|
||||
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
|
||||
|
||||
check_templates:
|
||||
stage: pretest
|
||||
script:
|
||||
- touch .htconfig.php
|
||||
- php util/precompile_smarty3.php
|
||||
|
||||
phpstan:
|
||||
stage: pretest
|
||||
script:
|
||||
- touch .htconfig.php
|
||||
- vendor/bin/phpstan --memory-limit=512M
|
||||
|
||||
# PHP8.2 with MySQL 8.0
|
||||
php8.2_mysql8.0.22:
|
||||
services:
|
||||
- mysql:8.0
|
||||
<<: *job_definition_mysql
|
||||
<<: *artifacts_template
|
||||
|
||||
# PHP8.1 with MariaDB 10.6
|
||||
php8.1_mariadb10.6:
|
||||
image: php:8.1
|
||||
# PHP8.2 with MariaDB 10.6
|
||||
php8.2_mariadb10.6:
|
||||
services:
|
||||
- name: mariadb:10.6
|
||||
alias: mysql
|
||||
<<: *job_definition_mysql
|
||||
<<: *artifacts_template
|
||||
|
||||
# PHP8.1 with PostgreSQL 12
|
||||
php8.1_postgres12:
|
||||
image: php:8.1
|
||||
# PHP8.2 with PostgreSQL 14
|
||||
php8.2_postgres14:
|
||||
services:
|
||||
- postgres:12-alpine
|
||||
- postgres:14-alpine
|
||||
<<: *job_definition_postgres
|
||||
<<: *artifacts_template
|
||||
|
||||
|
||||
236
CHANGELOG
236
CHANGELOG
@@ -1,3 +1,239 @@
|
||||
Hubzilla 10.6 (2025-11-04)
|
||||
Features
|
||||
- Improved background fetching of replies collection
|
||||
- Refactor ASCache and implement ASCache::isCacheable()
|
||||
- Implement ASCache in ASCollection to improve performance
|
||||
- Add json support for help index widget and add a new template
|
||||
- Implement hidden pconfig system.notifications_count_limit
|
||||
- Implement hidden pconfig system.invert_notifications_order
|
||||
- Implement mark seen button for unseen pubstream notifications
|
||||
- Iplemented per forum unseen items notifications
|
||||
- Intoduce Activity::pasteQuote() to paste the quote into the body at the right place if applicable and add test
|
||||
- Implement ASCache in Activity::get_quote()
|
||||
- Display webfinger address instead of channel URL in HQ widget notifications tab for consistency with other tabs
|
||||
- Implement FEP-e232 object links
|
||||
|
||||
Maintenance
|
||||
- Use a better supported json canonicalization library
|
||||
- CI: up PHP images to version 8.2
|
||||
- Enable gmp PHP extension in gitlab-ci
|
||||
- Update composer libs which now require gmp PHP extension
|
||||
- HTTPSig: return early if we got no key info
|
||||
- Removed deprecated conv_list template
|
||||
- Refactor PhotoGd::imageString() to reduce complexity
|
||||
- Add ImageQuality class to hold quality values
|
||||
- CI: introduce a quick test to check that smarty templates compile in the pretest stage
|
||||
- CI: upgrade to postgres 13
|
||||
- CI: add pretest step and run PHPStan
|
||||
- Updated Spanish strings
|
||||
- Remove redundant f arg in tagcloud widget
|
||||
- Remove dead code in handle_tag()
|
||||
- Enable unit tests for extensions
|
||||
- Remove obsolete phpunit configurations
|
||||
- Code cleanup
|
||||
|
||||
Bugfixes
|
||||
- Fix encoding for webpage, layout and block title and body when editing - issue #1946
|
||||
- Fix issues which prevented files and photos to be updated correctly after rename via DAV
|
||||
- Fix contact edit modal logic hijacking URL fragment on pages other than /connections
|
||||
- Fix deprecation notice in MessagesWidgetTest
|
||||
- Fix whole URL punified in mod follow
|
||||
- Fix whole URL punified in mod search
|
||||
- Fix setup check for zip PHP extension
|
||||
- Fix issue where remote channels could post to wall if they had write_storage permission - issue #1940
|
||||
- Fix not all notification icons updated
|
||||
- Fix notification icon not updated on medium screen size
|
||||
- Fix image/gif not handled in PhotoGd::imageString()
|
||||
- Fix issue where not all seen items where removed from the unseen notifications
|
||||
- Fix item_by_item_id() not returning Announce items - issue #1936
|
||||
- Fix archive widget not returning results if in single item mode - issue #1911
|
||||
- Fix db query in verify_email_address()
|
||||
- Fix search in mod channel only returning single post items - issue #1929
|
||||
- Fix commented out register_account hook breaking notify admin addon
|
||||
|
||||
Addon
|
||||
- Superblock: add tests
|
||||
- Wiki: fix photo embed buton for markdown
|
||||
- Pubcrawl: return early if we could not find an AS actor id and add some logging
|
||||
- Cart: adapt logic to fetch tpl from theme folder first
|
||||
- Cavatar: remove redundant arg from cavatar_init()
|
||||
|
||||
|
||||
Hubzilla 10.4.4 (2025-10-06)
|
||||
- Fix issue when confirming pending registrations
|
||||
- Fix TOS headings
|
||||
- Fix TOS paths
|
||||
- Add english TermsOfService.md
|
||||
- CI: skip ssl check
|
||||
|
||||
|
||||
Hubzilla 10.4.3 (2025-08-15)
|
||||
- Refactor module vote to prohibit double votes at the sender side
|
||||
- Fix vote answers counted as comments
|
||||
- Start transition of deprecated AS1 item.verb vocabulary to AS2 on demand in mod channel, articles and cards
|
||||
- Fix regression in retrieving channel address in wtagblock() and whitespace fixes
|
||||
|
||||
|
||||
Hubzilla 10.4.2 (2025-08-08)
|
||||
- Implement item_custom_display hook in mod HQ
|
||||
- Refactor item fetching functions to reflect item_normal() changes
|
||||
- Refactor item_normal() to optionally deal with various item types
|
||||
- Fix missing reactions modal in threaded_conversation.tpl
|
||||
- Improve memory consumption in drop_related() to fix deleting of big threads
|
||||
- Fix PHP error with the potential to stuff up the queueworker
|
||||
- Update the contact edit header so that both, image and text are linked to the profile
|
||||
- Articles: refactor to reflect item_normal() changes
|
||||
- Cards: refactor to reflect item_normal() changes
|
||||
|
||||
|
||||
Hubzilla 10.4.1 (2025-07-31)
|
||||
- Fix regression in pubstream tag view
|
||||
- Fix photos meta data not updated when renaming folder in files app
|
||||
- Fix syntax error in custom emoji sample code
|
||||
- Fix rendering issue when image load event triggered after timeout
|
||||
- Fix comment preview not always displayed
|
||||
- Fix new created comment rendering offscreen
|
||||
- Update derived theme tutorial and add it to the help index
|
||||
- Add 'extends' attribute to theme info
|
||||
- Fix reply modal remaining hidden after reactions loaded
|
||||
- Refactor tagcloud to use smarty template file
|
||||
- Fix regression in tagadelic
|
||||
- Fix possible performance issue with archive widget
|
||||
- Fix various addons which still used the deprecated $a global
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Zotlabs\Daemon;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\ASCollection;
|
||||
use Zotlabs\Lib\ASCache;
|
||||
|
||||
class Convo {
|
||||
|
||||
@@ -12,52 +13,66 @@ class Convo {
|
||||
|
||||
logger('convo invoked: ' . print_r($argv, true));
|
||||
|
||||
if ($argc != 4) {
|
||||
if ($argc < 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
$id = $argv[1];
|
||||
$channel_id = intval($argv[2]);
|
||||
$contact_hash = $argv[3];
|
||||
|
||||
$channel = channelx_by_n($channel_id);
|
||||
if (!$channel) {
|
||||
$channels = explode(',', $argv[1]);
|
||||
if (!$channels) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1",
|
||||
intval($channel_id),
|
||||
dbesc($contact_hash)
|
||||
);
|
||||
|
||||
if (!$r) {
|
||||
$observer_hash = $argv[2];
|
||||
if (!$observer_hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
$contact = array_shift($r);
|
||||
|
||||
$obj = new ASCollection($id, $channel);
|
||||
|
||||
$messages = $obj->get();
|
||||
|
||||
if (!$messages) {
|
||||
$mid = $argv[3];
|
||||
if (!$mid) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$message = Activity::fetch($message, $channel);
|
||||
$force = $argv[4] ?? false;
|
||||
|
||||
foreach ($channels as $channel_id) {
|
||||
$channel = channelx_by_n($channel_id);
|
||||
|
||||
$obj = new ASCollection($mid, $channel);
|
||||
|
||||
$messages = $obj->get();
|
||||
|
||||
if (!$messages) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set client flag because comments will probably just be objects and not full blown activities
|
||||
// and that lets us use implied_create
|
||||
$AS = new ActivityStreams($message);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
$item['item_fetched'] = true;
|
||||
Activity::store($channel, $contact['abook_xchan'], $AS, $item);
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$cached = ASCache::Get($message);
|
||||
if ($cached) {
|
||||
// logger('convo_cached: ' . $message);
|
||||
$data = $cached;
|
||||
}
|
||||
else {
|
||||
// logger('convo_fetching: ' . $message);
|
||||
$data = Activity::fetch($message, $channel);
|
||||
if ($data) {
|
||||
ASCache::Set($message, $data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
$data = $message;
|
||||
}
|
||||
|
||||
$AS = new ActivityStreams($data);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
$item['item_fetched'] = true;
|
||||
Activity::store($channel, $observer_hash, $AS, $item, false, $force);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -36,6 +36,8 @@ class Fetchparents {
|
||||
Activity::fetch_and_store_parents($channel, $observer_hash, $mid, null, $force);
|
||||
}
|
||||
|
||||
Activity::init_background_fetch($observer_hash);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -7,27 +7,63 @@ namespace Zotlabs\Lib;
|
||||
*/
|
||||
|
||||
class ASCache {
|
||||
public static function isEnabled() {
|
||||
public static function isEnabled()
|
||||
{
|
||||
return Config::Get('system', 'as_object_cache_enabled', true);
|
||||
}
|
||||
|
||||
public static function getAge() {
|
||||
public static function getAge(): string
|
||||
{
|
||||
return Config::Get('system', 'as_object_cache_time', '10 MINUTE');
|
||||
}
|
||||
|
||||
public static function Get($key) {
|
||||
public static function Get(string $key): array
|
||||
{
|
||||
if (!self::isEnabled()) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
return Cache::get($key, self::getAge());
|
||||
$ret = Cache::get($key, self::getAge());
|
||||
|
||||
if ($ret) {
|
||||
return unserialise($ret);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function Set($key, $value) {
|
||||
public static function Set(string $key, array $obj): void
|
||||
{
|
||||
if (!self::isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Cache::set($key, $value);
|
||||
if (!self::isCacheable($obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Cache::set($key, serialise($obj));
|
||||
}
|
||||
|
||||
public static function isCacheable(array $obj): bool
|
||||
{
|
||||
$to = [];
|
||||
$cc = [];
|
||||
|
||||
if (isset($obj['to'])) {
|
||||
$to = is_array($obj['to']) ? $obj['to'] : [$obj['to']];
|
||||
}
|
||||
|
||||
if (isset($obj['cc'])) {
|
||||
$cc = is_array($obj['cc']) ? $obj['cc'] : [$obj['cc']];
|
||||
}
|
||||
|
||||
$receivers = array_merge($to, $cc);
|
||||
|
||||
if ($receivers && !in_array(ACTIVITY_PUBLIC_INBOX, $receivers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,19 @@ class ASCollection {
|
||||
}
|
||||
|
||||
if (is_string($obj)) {
|
||||
$data = Activity::fetch($obj, $channel);
|
||||
$cached = ASCache::Get($obj);
|
||||
if ($cached) {
|
||||
// logger('cached: ' . $obj);
|
||||
$data = $cached;
|
||||
}
|
||||
else {
|
||||
// logger('fetching: ' . $obj);
|
||||
$data = Activity::fetch($obj, $channel);
|
||||
if ($data) {
|
||||
ASCache::Set($obj, $data);
|
||||
}
|
||||
}
|
||||
|
||||
$this->history[] = $obj;
|
||||
}
|
||||
|
||||
@@ -92,7 +104,20 @@ class ASCollection {
|
||||
// recursion detected
|
||||
return false;
|
||||
}
|
||||
$data = Activity::fetch($this->nextpage, $this->channel);
|
||||
|
||||
$cached = ASCache::Get($this->nextpage);
|
||||
if ($cached) {
|
||||
// logger('cached: ' . $this->nextpage);
|
||||
$data = $cached;
|
||||
}
|
||||
else {
|
||||
$data = Activity::fetch($this->nextpage, $this->channel);
|
||||
if ($data) {
|
||||
// logger('fetching: ' . $this->nextpage);
|
||||
ASCache::Set($this->nextpage, $data);
|
||||
}
|
||||
}
|
||||
|
||||
$this->history[] = $this->nextpage;
|
||||
}
|
||||
|
||||
|
||||
@@ -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'] .= ' ';
|
||||
@@ -621,15 +620,6 @@ class Activity {
|
||||
$ret['context'] = $cnv;
|
||||
}
|
||||
|
||||
if ($i['mimetype'] === 'text/bbcode') {
|
||||
if ($i['title'])
|
||||
$ret['name'] = unescape_tags($i['title']);
|
||||
if ($i['summary'])
|
||||
$ret['summary'] = unescape_tags($i['summary']);
|
||||
$ret['content'] = bbcode(unescape_tags($i['body']), ['cache' => true]);
|
||||
$ret['source'] = ['content' => unescape_tags($i['body']), 'mediaType' => 'text/bbcode'];
|
||||
}
|
||||
|
||||
$actor = self::encode_person($i['author'], false);
|
||||
if ($actor)
|
||||
$ret['actor'] = $actor;
|
||||
@@ -647,6 +637,53 @@ class Activity {
|
||||
$ret['tag'] = $t;
|
||||
}
|
||||
|
||||
if (str_contains($i['body'], '[/share]')) {
|
||||
preg_match_all('/\[share(.*?)\[\/share\]/ism', $i['body'], $all_shares, PREG_SET_ORDER);
|
||||
|
||||
$quote_urls = [];
|
||||
|
||||
foreach ($all_shares as $share) {
|
||||
// Extract the link attribute from each [share] block
|
||||
if (preg_match("/link='(.*?)'/ism", $share[1], $match)) {
|
||||
$url = $match[1];
|
||||
$quote_urls[] = $url;
|
||||
|
||||
$quote_name = 'RE: ' . $url;
|
||||
|
||||
// Replace this share block with a formatted URL reference
|
||||
$i['body'] = str_replace($share[0], $quote_name, $i['body']);
|
||||
|
||||
$obj_links[] = [
|
||||
'type' => 'Link',
|
||||
'mediaType' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
'href' => $url,
|
||||
'name' => $quote_name
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($quote_urls) {
|
||||
$ret['quoteUrl'] = $quote_urls[0];
|
||||
|
||||
if (empty($ret['tag'])) {
|
||||
$ret['tag'] = $obj_links;
|
||||
}
|
||||
else {
|
||||
$ret['tag'] = array_merge($ret['tag'], $obj_links);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($i['mimetype'] === 'text/bbcode') {
|
||||
if ($i['title'])
|
||||
$ret['name'] = unescape_tags($i['title']);
|
||||
if ($i['summary'])
|
||||
$ret['summary'] = unescape_tags($i['summary']);
|
||||
$ret['content'] = bbcode(unescape_tags($i['body']));
|
||||
$ret['source'] = ['content' => unescape_tags($i['body']), 'mediaType' => 'text/bbcode'];
|
||||
}
|
||||
|
||||
$a = self::encode_attachment($i);
|
||||
if ($a) {
|
||||
$ret['attachment'] = $a;
|
||||
@@ -695,7 +732,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'])];
|
||||
@@ -710,7 +747,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:
|
||||
@@ -853,6 +890,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);
|
||||
@@ -942,36 +981,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) {
|
||||
@@ -986,15 +997,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'
|
||||
@@ -1010,7 +1021,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'])) {
|
||||
@@ -1062,7 +1073,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);
|
||||
}
|
||||
@@ -1090,7 +1101,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);
|
||||
}
|
||||
@@ -1101,12 +1112,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) {
|
||||
@@ -1117,7 +1126,6 @@ class Activity {
|
||||
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
|
||||
}
|
||||
|
||||
|
||||
$hookinfo = [
|
||||
'item' => $i,
|
||||
'encoded' => $ret
|
||||
@@ -2148,34 +2156,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 +2213,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 +2225,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 +2263,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,18 +2314,46 @@ 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'));
|
||||
|
||||
if ($act->objprop('quoteUrl')) {
|
||||
$quote_bbcode = self::get_quote_bbcode($act->obj['quoteUrl']);
|
||||
// peertube quirks
|
||||
if ($act->objprop('mediaType') === 'text/markdown') {
|
||||
$s['body'] = markdown_to_bb($act->objprop('content'));
|
||||
}
|
||||
|
||||
if ($s['body']) {
|
||||
$s['body'] .= "\r\n\r\n";
|
||||
$quote_urls = [];
|
||||
|
||||
if (isset($act->obj['tag'])) {
|
||||
foreach($act->obj['tag'] as $t) {
|
||||
if (is_array($t) && $t['type'] === 'Link' && $t['mediaType'] === 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"') {
|
||||
$quote_urls[] = $t['href'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$s['body'] .= $quote_bbcode;
|
||||
if (!$quote_urls) {
|
||||
$quote_url = $act->obj['quoteUrl'] ?? $act->obj['quoteUri'] ?? $act->obj['_misskey_quote'] ?? $act->obj['quote'] ?? null;
|
||||
|
||||
if ($quote_url) {
|
||||
$quote_urls = [$quote_url];
|
||||
}
|
||||
}
|
||||
|
||||
// Backwards compatibility: only process quote items if there is no share tag in them.
|
||||
// Otherwise they will appear doubled.
|
||||
if ($quote_urls && !str_contains($s['body'], '[/share]')) {
|
||||
foreach($quote_urls as $quote_url) {
|
||||
$quote = self::get_quote($quote_url);
|
||||
|
||||
if (!$quote) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$s['body'] = self::pasteQuote($s['body'], $quote);
|
||||
$s['term'] = $quote['term'];
|
||||
}
|
||||
}
|
||||
|
||||
$s['verb'] = self::activity_mapper($act->type);
|
||||
@@ -2394,7 +2401,13 @@ class Activity {
|
||||
$a = self::decode_taxonomy($act->obj);
|
||||
|
||||
if ($a) {
|
||||
$s['term'] = $a;
|
||||
if (isset($s['term'])) {
|
||||
// term might contain content from a quote post
|
||||
$s['term'] = array_merge($s['term'], $a);
|
||||
}
|
||||
else {
|
||||
$s['term'] = $a;
|
||||
}
|
||||
}
|
||||
|
||||
$a = self::decode_attachment($act->obj);
|
||||
@@ -2470,7 +2483,8 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
$tag = (($poster) ? '[video poster="' . $poster . '"]' : '[video]' );
|
||||
$tag = (($poster) ? '[video poster=\'' . $poster . '\']' : '[video]' );
|
||||
|
||||
$ptr = null;
|
||||
|
||||
if ($act->objprop('url')) {
|
||||
@@ -2619,7 +2633,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($act->objprop('type'), ['Note', 'Article', 'Page'])) {
|
||||
if (in_array($act->objprop('type'), ['Note', 'Article', 'Page', 'Question'])) {
|
||||
$ptr = null;
|
||||
|
||||
if (array_key_exists('url', $act->obj)) {
|
||||
@@ -2631,7 +2645,7 @@ class Activity {
|
||||
$ptr = [$act->obj['url']];
|
||||
}
|
||||
foreach ($ptr as $vurl) {
|
||||
if (array_key_exists('mediaType', $vurl) && $vurl['mediaType'] === 'text/html') {
|
||||
if (isset($vurl['mediaType']) && $vurl['mediaType'] === 'text/html') {
|
||||
$s['plink'] = $vurl['href'];
|
||||
break;
|
||||
}
|
||||
@@ -2643,7 +2657,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if (!(isset($s['plink']) && $s['plink'])) {
|
||||
if (empty($s['plink'])) {
|
||||
$s['plink'] = $s['mid'];
|
||||
}
|
||||
|
||||
@@ -2719,8 +2733,9 @@ class Activity {
|
||||
return $hookinfo['s'];
|
||||
|
||||
}
|
||||
|
||||
static function store($channel, $observer_hash, $act, $item, $fetch_parents = true, $force = false, $is_collection_operation = false) {
|
||||
$is_sys_channel = is_sys_channel($channel['channel_id']);
|
||||
$is_sys_channel = $channel['channel_system'];
|
||||
$is_child_node = false;
|
||||
$parent = null;
|
||||
|
||||
@@ -2767,7 +2782,9 @@ class Activity {
|
||||
$force = true;
|
||||
}
|
||||
|
||||
if ($fetch_parents) {
|
||||
$attempt_parents_fetch = $fetch_parents && !in_array($channel['channel_id'], App::$cache['as_fetch_objects'][$item['mid']]['channels'] ?? []);
|
||||
|
||||
if ($attempt_parents_fetch) {
|
||||
App::$cache['as_fetch_objects'][$item['mid']]['channels'][] = $channel['channel_id'];
|
||||
App::$cache['as_fetch_objects'][$item['mid']]['force'] = intval($force);
|
||||
return;
|
||||
@@ -2780,7 +2797,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;
|
||||
}
|
||||
@@ -2943,7 +2960,7 @@ class Activity {
|
||||
if (!$item['author_xchan'] || !$item['owner_xchan'])
|
||||
return;
|
||||
|
||||
if ($channel['channel_system']) {
|
||||
if ($is_sys_channel) {
|
||||
$incl = Config::Get('system','pubstream_incl');
|
||||
$excl = Config::Get('system','pubstream_excl');
|
||||
|
||||
@@ -3012,7 +3029,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'] = '';
|
||||
}
|
||||
@@ -3029,7 +3046,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) {
|
||||
@@ -3043,6 +3060,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: not implemented
|
||||
// self::rewrite_mentions($item);
|
||||
@@ -3066,8 +3084,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);
|
||||
}
|
||||
|
||||
@@ -3085,38 +3102,17 @@ 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']);
|
||||
}
|
||||
|
||||
if ($fetch_parents && $parent && !intval($parent[0]['item_private'])) {
|
||||
logger('topfetch', LOGGER_DEBUG);
|
||||
// if the thread owner is a connnection, we will already receive any additional comments to their posts
|
||||
// but if they are not we can try to fetch others in the background
|
||||
$connected = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1",
|
||||
intval($channel['channel_id']),
|
||||
dbesc($parent[0]['owner_xchan'])
|
||||
);
|
||||
if (!$connected) {
|
||||
// determine if the top-level post provides a replies collection
|
||||
if ($parent[0]['obj']) {
|
||||
$parent[0]['obj'] = json_decode($parent[0]['obj'], true);
|
||||
}
|
||||
logger('topfetch: ' . print_r($parent[0], true), LOGGER_ALL);
|
||||
$id = ((array_path_exists('obj/replies/id', $parent[0])) ? $parent[0]['obj']['replies']['id'] : false);
|
||||
if (!$id) {
|
||||
$id = ((array_path_exists('obj/replies', $parent[0]) && is_string($parent[0]['obj']['replies'])) ? $parent[0]['obj']['replies'] : false);
|
||||
}
|
||||
if ($id) {
|
||||
Master::Summon(['Convo', $id, $channel['channel_id'], $observer_hash]);
|
||||
}
|
||||
// Only store replies collection for background fetching if the item has been fetched.
|
||||
// A message that has just been posted usually will not have any replies yet.
|
||||
// Also dismiss duplicates.
|
||||
$attempt_replies_fetch = isset($act->obj['replies']['id']) && !empty($item['item_fetched']) && !in_array($channel['channel_id'], App::$cache['as_fetch_collection'][$act->obj['replies']['id']]['channels'] ?? []);
|
||||
if ($attempt_replies_fetch) {
|
||||
App::$cache['as_fetch_collection'][$act->obj['replies']['id']]['channels'][] = $channel['channel_id'];
|
||||
App::$cache['as_fetch_collection'][$act->obj['replies']['id']]['force'] = intval($force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3165,7 +3161,7 @@ class Activity {
|
||||
$cached = ASCache::Get($current_item['parent_mid']);
|
||||
if ($cached) {
|
||||
// logger('cached: ' . $current_item['parent_mid']);
|
||||
$n = unserialise($cached);
|
||||
$n = $cached;
|
||||
}
|
||||
else {
|
||||
// logger('fetching: ' . $current_item['parent_mid']);
|
||||
@@ -3173,7 +3169,7 @@ class Activity {
|
||||
if (!$n) {
|
||||
break;
|
||||
}
|
||||
ASCache::Set($current_item['parent_mid'], serialise($n));
|
||||
ASCache::Set($current_item['parent_mid'], $n);
|
||||
}
|
||||
|
||||
$a = new ActivityStreams($n);
|
||||
@@ -3408,10 +3404,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;
|
||||
@@ -3610,38 +3606,68 @@ 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;
|
||||
}
|
||||
|
||||
static function get_quote_bbcode($url) {
|
||||
static function get_quote($url) {
|
||||
$ret = [];
|
||||
$a = null;
|
||||
|
||||
$cached = ASCache::Get($url);
|
||||
if ($cached) {
|
||||
// logger('cached: ' . $url);
|
||||
$a = unserialise($cached);
|
||||
}
|
||||
else {
|
||||
// logger('fetching: ' . $url);
|
||||
$a = self::fetch($url);
|
||||
if ($a) {
|
||||
ASCache::Set($url, $a);
|
||||
}
|
||||
}
|
||||
|
||||
$ret = '';
|
||||
|
||||
$a = self::fetch($url);
|
||||
if ($a) {
|
||||
$act = new ActivityStreams($a);
|
||||
|
||||
if ($act->is_valid()) {
|
||||
$content = self::get_content($act->obj);
|
||||
$decoded = self::decode_note($act);
|
||||
|
||||
$ret .= "[share author='" . urlencode($act->actor['name'] ?? $act->actor['preferredUsername']) .
|
||||
$bbcode = "[share author='" . urlencode($act->actor['name'] ?? $act->actor['preferredUsername']) .
|
||||
"' profile='" . $act->actor['id'] .
|
||||
"' avatar='" . ($act->actor['icon']['url'] ?? z_root() . '/' . get_default_profile_photo(80)) .
|
||||
"' link='" . $act->obj['id'] .
|
||||
"' link='" . $url .
|
||||
"' auth='" . ((is_matrix_url($act->actor['id'])) ? 'true' : 'false') .
|
||||
"' posted='" . $act->obj['published'] .
|
||||
"' message_id='" . $act->obj['id'] .
|
||||
"']";
|
||||
$ret .= self::bb_content($content, 'content');
|
||||
$ret .= '[/share]';
|
||||
|
||||
$bbcode .= $decoded['body'];
|
||||
$bbcode .= '[/share]';
|
||||
|
||||
$ret['bbcode'] = $bbcode;
|
||||
$ret['url'] = $decoded['plink'];
|
||||
$ret['mid'] = $decoded['mid'];
|
||||
$ret['term'] = $decoded['term'] ?? [];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3721,7 +3747,9 @@ class Activity {
|
||||
'guid' => 'diaspora:guid',
|
||||
|
||||
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
|
||||
'Hashtag' => 'as:Hashtag'
|
||||
'Hashtag' => 'as:Hashtag',
|
||||
|
||||
'quoteUrl' => 'as:quoteUrl',
|
||||
];
|
||||
|
||||
}
|
||||
@@ -3761,10 +3789,9 @@ class Activity {
|
||||
|
||||
public static function init_background_fetch(string $observer_hash = '') {
|
||||
if (isset(App::$cache['zot_fetch_objects'])) {
|
||||
$channels_str = '';
|
||||
|
||||
foreach (App::$cache['zot_fetch_objects'] as $mid => $info) {
|
||||
$force = $info['force'];
|
||||
$channels_str = '';
|
||||
|
||||
foreach ($info['channels'] as $c) {
|
||||
if ($channels_str) {
|
||||
@@ -3777,16 +3804,15 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if (!$observer_hash) {
|
||||
logger('Attempt to initiate Fetchparents or Convo daemon without observer');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset(App::$cache['as_fetch_objects'])) {
|
||||
if (!$observer_hash) {
|
||||
logger('Attempt to initiate Fetchparents daemon without observer');
|
||||
return;
|
||||
}
|
||||
|
||||
$channels_str = '';
|
||||
|
||||
foreach (App::$cache['as_fetch_objects'] as $mid => $info) {
|
||||
$force = $info['force'];
|
||||
$channels_str = '';
|
||||
|
||||
foreach ($info['channels'] as $c) {
|
||||
if ($channels_str) {
|
||||
@@ -3798,6 +3824,23 @@ class Activity {
|
||||
Master::Summon(['Fetchparents', $channels_str, $observer_hash, $mid, $force]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset(App::$cache['as_fetch_collection'])) {
|
||||
foreach (App::$cache['as_fetch_collection'] as $mid => $info) {
|
||||
$force = $info['force'];
|
||||
$channels_str = '';
|
||||
|
||||
foreach ($info['channels'] as $c) {
|
||||
if ($channels_str) {
|
||||
$channels_str .= ',';
|
||||
}
|
||||
$channels_str .= $c;
|
||||
}
|
||||
|
||||
Master::Summon(['Convo', $channels_str, $observer_hash, $mid, $force]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function addToCollection($channel, $object, $target, $sourceItem = null, $deliver = true) {
|
||||
@@ -3872,4 +3915,69 @@ 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)
|
||||
?? '';
|
||||
}
|
||||
|
||||
public static function pasteQuote(string $body, array $quote): string
|
||||
{
|
||||
// Escape URLs for regex safety
|
||||
$urls = array_map('preg_quote', [$quote['url'], $quote['mid']], array_fill(0, 2, '/'));
|
||||
|
||||
$patterns = [];
|
||||
foreach ($urls as $url) {
|
||||
// Match both plain and BBCode-style references, with optional line breaks or spaces
|
||||
$patterns[] = '/RE:\s*(?:\[url=' . $url . '\]' . $url . '\[\/url\]|' . $url . ')[\s\r\n]?/i';
|
||||
}
|
||||
|
||||
$found = false;
|
||||
foreach ($patterns as $pattern) {
|
||||
if (preg_match($pattern, $body)) {
|
||||
$found = true;
|
||||
$body = preg_replace($pattern, $quote['bbcode'], $body);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
if (!empty($body)) {
|
||||
$body .= "\r\n\r\n";
|
||||
}
|
||||
$body .= $quote['bbcode'];
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class ActivityStreams {
|
||||
}
|
||||
|
||||
// cache for future use
|
||||
ASCache::Set($this->id, 'json:' . $this->raw);
|
||||
ASCache::Set($this->id, $this->data);
|
||||
|
||||
$this->type = $this->get_primary_type();
|
||||
$this->actor = $this->get_actor('actor', '', '');
|
||||
@@ -413,13 +413,13 @@ class ActivityStreams {
|
||||
$cached = ASCache::Get($x);
|
||||
if ($cached) {
|
||||
// logger('AS cached: ' . $x);
|
||||
$y = unserialise($cached);
|
||||
$y = $cached;
|
||||
}
|
||||
else {
|
||||
// logger('AS fetching: ' . $x);
|
||||
$y = $this->fetch_property($x);
|
||||
if ($y) {
|
||||
ASCache::Set($x, serialise($y));
|
||||
ASCache::Set($x, $y);
|
||||
}
|
||||
}
|
||||
if (is_array($y)) {
|
||||
@@ -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'),
|
||||
|
||||
@@ -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'));
|
||||
|
||||
}
|
||||
|
||||
@@ -271,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();
|
||||
@@ -327,6 +327,9 @@ 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 ($parent_item['author']['xchan_hash'] === $recip['channel_hash']) {
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
@@ -508,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'];
|
||||
@@ -569,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'])
|
||||
);
|
||||
@@ -848,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'])) {
|
||||
@@ -861,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']));
|
||||
}
|
||||
|
||||
|
||||
@@ -886,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)),
|
||||
@@ -906,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'],
|
||||
@@ -925,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'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,33 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Mmccook\JsonCanonicalizator\JsonCanonicalizatorFactory;
|
||||
use Root23\JsonCanonicalizer\JsonCanonicalizer;
|
||||
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 = [
|
||||
@@ -85,8 +102,8 @@ class JcsEddsa2022 {
|
||||
}
|
||||
|
||||
public function canonicalize($data) {
|
||||
$canonicalization = JsonCanonicalizatorFactory::getInstance();
|
||||
return $canonicalization->canonicalize($data);
|
||||
$canonicalizer = new JsonCanonicalizer();
|
||||
return $canonicalizer->canonicalize($data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1169,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)) {
|
||||
@@ -1546,6 +1542,7 @@ class Libzot {
|
||||
|
||||
$local_public = $public;
|
||||
$item_result = null;
|
||||
$parent = null;
|
||||
|
||||
$DR = new DReport(z_root(), $sender, $d, $arr['mid'], $arr['uuid']);
|
||||
|
||||
@@ -1853,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'])
|
||||
);
|
||||
|
||||
@@ -2007,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 '';
|
||||
}
|
||||
|
||||
@@ -803,7 +813,7 @@ class ThreadItem {
|
||||
'$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'),
|
||||
@@ -834,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 = '';
|
||||
|
||||
@@ -842,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;
|
||||
@@ -862,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);
|
||||
|
||||
@@ -9,7 +9,7 @@ trait HelpHelperTrait {
|
||||
// PHP versions before 8.2 does not support trait constants,
|
||||
// Leave this commented out until we drop support for PHP 8.1.
|
||||
//
|
||||
// const VALID_FILE_EXT = ['md', 'bb', 'html'];
|
||||
// const VALID_FILE_EXT = ['md', 'bb', 'html', 'json'];
|
||||
|
||||
private string $file_name = '';
|
||||
private string $file_type = '';
|
||||
@@ -58,7 +58,7 @@ trait HelpHelperTrait {
|
||||
private function find_help_file(string $base_path, string $lang): void {
|
||||
|
||||
// Use local variable until we can use trait constants.
|
||||
$valid_file_ext = ['md', 'bb', 'html'];
|
||||
$valid_file_ext = ['md', 'bb', 'html', 'json'];
|
||||
|
||||
$base_path_with_lang = "doc/{$lang}/${base_path}";
|
||||
|
||||
@@ -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,7 +23,7 @@ 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),
|
||||
@@ -166,6 +166,7 @@ class Activity extends Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$portable_id = null;
|
||||
$ob_authorize = false;
|
||||
$item_uid = 0;
|
||||
|
||||
|
||||
@@ -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));
|
||||
@@ -243,7 +243,7 @@ class Channel extends Controller {
|
||||
// search terms header
|
||||
if ($search) {
|
||||
$o .= replace_macros(get_markup_template("section_title.tpl"), [
|
||||
'$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT, 'UTF-8')
|
||||
'$title' => t('Searching for:') . ' ' . htmlspecialchars($search, ENT_COMPAT, 'UTF-8')
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -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 item.parent AS item_id, item.verb from item where $identifier = '%s' and item.uid = %d $item_normal
|
||||
AND item.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 item.parent AS item_id, item.verb, $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,20 @@ class Channel extends Controller {
|
||||
}
|
||||
}
|
||||
if ($r) {
|
||||
$parents_str = ids_to_querystr($r, 'item_id');
|
||||
|
||||
$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)
|
||||
);
|
||||
// 11.08.2025 start transition deprecated AS1 item.verb vocabulary to AS2 on demand.
|
||||
// Keep this until we officially deprecate AS1 data.
|
||||
AS1_to_AS2_verbs($r);
|
||||
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
$thr_parents = null;
|
||||
if ($mid) {
|
||||
$thr_parents = get_recursive_thr_parents($r[0]);
|
||||
}
|
||||
|
||||
$items = items_by_parent_ids($r, $thr_parents, $permission_sql, $blog_mode);
|
||||
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$items = conv_sort($items, $ordering);
|
||||
|
||||
if ($load && $mid && (!count($items))) {
|
||||
@@ -434,10 +444,7 @@ class Channel extends Controller {
|
||||
$items = [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
$mode = (($search) ? 'search' : 'channel');
|
||||
|
||||
$mode = 'channel';
|
||||
|
||||
if ((!$update) && (!$load)) {
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -122,10 +122,10 @@ class Editblock extends \Zotlabs\Web\Controller {
|
||||
'ptyp' => $itm[0]['type'],
|
||||
'mimeselect' => true,
|
||||
'mimetype' => $itm[0]['mimetype'],
|
||||
'body' => undo_post_tagging($content),
|
||||
'body' => htmlspecialchars_decode(undo_post_tagging($content), ENT_COMPAT),
|
||||
'post_id' => $post_id,
|
||||
'visitor' => true,
|
||||
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
||||
'title' => htmlspecialchars_decode($itm[0]['title'], ENT_COMPAT),
|
||||
'placeholdertitle' => t('Title (optional)'),
|
||||
'pagetitle' => $block_title,
|
||||
'profile_uid' => (intval($channel['channel_id'])),
|
||||
|
||||
@@ -121,9 +121,9 @@ class Editlayout extends \Zotlabs\Web\Controller {
|
||||
'hide_preview' => true,
|
||||
'disable_comments' => true,
|
||||
'ptyp' => $itm[0]['obj_type'],
|
||||
'body' => undo_post_tagging($itm[0]['body']),
|
||||
'body' => htmlspecialchars_decode(undo_post_tagging($itm[0]['body']), ENT_COMPAT),
|
||||
'post_id' => $post_id,
|
||||
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
||||
'title' => htmlspecialchars_decode($itm[0]['title'], ENT_COMPAT),
|
||||
'pagetitle' => $layout_title,
|
||||
'ptlabel' => t('Layout Name'),
|
||||
'placeholdertitle' => t('Layout Description (Optional)'),
|
||||
|
||||
@@ -144,7 +144,7 @@ class Editwebpage extends \Zotlabs\Web\Controller {
|
||||
'hide_location' => true,
|
||||
'hide_voting' => true,
|
||||
'ptyp' => $itm[0]['type'],
|
||||
'body' => undo_post_tagging($content),
|
||||
'body' => htmlspecialchars_decode(undo_post_tagging($content), ENT_COMPAT),
|
||||
'post_id' => $post_id,
|
||||
'visitor' => ($is_owner) ? true : false,
|
||||
'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
|
||||
@@ -154,7 +154,7 @@ class Editwebpage extends \Zotlabs\Web\Controller {
|
||||
'mimeselect' => true,
|
||||
'layout' => $layout,
|
||||
'layoutselect' => true,
|
||||
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
||||
'title' => htmlspecialchars_decode($itm[0]['title'], ENT_COMPAT),
|
||||
'lockstate' => (((strlen($itm[0]['allow_cid'])) || (strlen($itm[0]['allow_gid'])) || (strlen($itm[0]['deny_cid'])) || (strlen($itm[0]['deny_gid']))) ? 'lock' : 'unlock'),
|
||||
'profile_uid' => (intval($owner)),
|
||||
'bbcode' => (($mimetype == 'text/bbcode') ? true : false)
|
||||
|
||||
@@ -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']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,14 @@ class Follow extends Controller {
|
||||
}
|
||||
|
||||
$uid = local_channel();
|
||||
$url = notags(punify(trim($_REQUEST['url'])));
|
||||
$url = notags(trim($_REQUEST['url']));
|
||||
|
||||
$parsed = parse_url($url);
|
||||
if (isset($parsed['host'])) {
|
||||
$parsed['host'] = punify($parsed['host']);
|
||||
$url = unparse_url($parsed);
|
||||
}
|
||||
|
||||
$return_url = $_SESSION['return_url'];
|
||||
$interactive = $_REQUEST['interactive'] ?? 1;
|
||||
$channel = App::get_channel();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Widget\Messages;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Hq extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -50,14 +51,18 @@ 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];
|
||||
|
||||
call_hooks('item_custom_display', $target_item);
|
||||
|
||||
if (intval($target_item['uid']) === intval($sys['channel_id'])) {
|
||||
$sys_item = true;
|
||||
}
|
||||
@@ -86,7 +91,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 +134,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 +150,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 +203,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,12 +53,12 @@ class Item extends Controller {
|
||||
|
||||
|
||||
if (argc() > 1 && argv(1) !== 'drop') {
|
||||
$x = q("select uid, item_wall, llink, uuid from item where uuid = '%s' order by item_wall desc",
|
||||
$x = q("select uid, item_wall, item_type, llink, uuid from item where uuid = '%s' order by item_wall desc",
|
||||
dbesc(argv(1))
|
||||
);
|
||||
|
||||
if ($x) {
|
||||
if ($x[0]['item_wall']) {
|
||||
if ($x[0]['item_wall'] && $x[0]['item_type'] === ITEM_TYPE_POST) {
|
||||
$c = channelx_by_n($x[0]['uid']);
|
||||
if ($c) {
|
||||
goaway(z_root() . '/channel/' . $c['channel_address'] . '?mid=' . $x[0]['uuid']);
|
||||
@@ -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();
|
||||
}
|
||||
@@ -391,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();
|
||||
}
|
||||
@@ -425,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);
|
||||
@@ -451,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'];
|
||||
@@ -491,11 +496,11 @@ class Item extends Controller {
|
||||
}
|
||||
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) {
|
||||
|
||||
@@ -510,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)));
|
||||
|
||||
@@ -530,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'];
|
||||
}
|
||||
|
||||
|
||||
@@ -541,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();
|
||||
}
|
||||
@@ -549,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';
|
||||
@@ -591,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 = '';
|
||||
@@ -790,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);
|
||||
@@ -798,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;
|
||||
@@ -847,10 +850,10 @@ class Item extends Controller {
|
||||
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);
|
||||
|
||||
|
||||
@@ -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'], type: $arr['item']['item_type']);
|
||||
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
|
||||
@@ -139,7 +127,7 @@ class Like extends Controller {
|
||||
$extended_like = false;
|
||||
$object = $target = null;
|
||||
$post_type = EMPTY_STR;
|
||||
$obj_type = EMPTY_STR;
|
||||
$obj_type = EMPTY_STR;
|
||||
|
||||
if (argc() == 3) {
|
||||
|
||||
@@ -317,8 +305,6 @@ class Like extends Controller {
|
||||
// parent, copy that as well.
|
||||
|
||||
if ($r) {
|
||||
$obj_type = $r[0]['obj_type'];
|
||||
|
||||
if ($r[0]['uid'] === $sys_channel['channel_id'] && local_channel()) {
|
||||
$r = [copy_of_pubitem(App::get_channel(), $r[0]['mid'])];
|
||||
}
|
||||
@@ -334,6 +320,8 @@ class Like extends Controller {
|
||||
$item = $r[0];
|
||||
$owner_uid = $r[0]['uid'];
|
||||
$owner_aid = $r[0]['aid'];
|
||||
$obj_type = $r[0]['obj_type'];
|
||||
$item_type = $r[0]['item_type'];
|
||||
|
||||
if ((array_key_exists('owner', $item)) && intval($item['owner']['abook_self']))
|
||||
$can_comment = perm_is_allowed($item['uid'], $observer['xchan_hash'], 'post_comments');
|
||||
@@ -374,7 +362,7 @@ class Like extends Controller {
|
||||
$multi_undo = true;
|
||||
}
|
||||
|
||||
$item_normal = item_normal();
|
||||
$item_normal = item_normal(type: $item_type);
|
||||
|
||||
$r = q("SELECT id, parent, uid, verb FROM item WHERE verb in ( $verbs ) $item_normal
|
||||
AND author_xchan = '%s' AND thr_parent = '%s' and uid = %d ",
|
||||
@@ -445,7 +433,7 @@ class Like extends Controller {
|
||||
$arr['item_wall'] = 1;
|
||||
}
|
||||
else {
|
||||
switch ($item['object_type']) {
|
||||
switch ($item['obj_type']) {
|
||||
case 'Image':
|
||||
$post_type = t('image');
|
||||
break;
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ class Lockview extends Controller {
|
||||
// as unknown specific recipients. The sender will have the visibility list and will fall through to the
|
||||
// next section.
|
||||
|
||||
echo '<div class="dropdown-item-text">' . translate_scope((!$item['public_policy']) ? 'specific' : $item['public_policy']) . '</div>';
|
||||
echo '<div class="dropdown-item-text">' . escape_tags(translate_scope((!$item['public_policy']) ? 'specific' : $item['public_policy'])) . '</div>';
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,17 @@ namespace Zotlabs\Module;
|
||||
class Login extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
if(local_channel())
|
||||
if (local_channel()) {
|
||||
goaway(z_root());
|
||||
if(remote_channel() && $_SESSION['atoken'])
|
||||
}
|
||||
|
||||
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">';
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -142,12 +138,14 @@ class Magic extends Controller {
|
||||
$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)
|
||||
@@ -133,7 +135,6 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
|
||||
$status_editor = '';
|
||||
|
||||
|
||||
if (Apps::system_app_installed(local_channel(), 'Affinity Tool')) {
|
||||
$affinity_locked = intval(get_pconfig(local_channel(), 'affinity', 'lock', 1));
|
||||
if ($affinity_locked) {
|
||||
@@ -201,7 +202,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,
|
||||
@@ -271,39 +272,9 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
// This is for nouveau view cid queries (not a public forum)
|
||||
$sql_extra = " AND author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ";
|
||||
}
|
||||
elseif($pf && $unseen && $nouveau) {
|
||||
|
||||
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify');
|
||||
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'])
|
||||
//);
|
||||
|
||||
//$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 +364,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) ';
|
||||
}
|
||||
|
||||
|
||||
@@ -405,17 +376,9 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
$sql_extra .= " AND ( author_xchan = '" . dbesc($channel['channel_hash']) . "' OR item_mentionsme = 1 ) ";
|
||||
}
|
||||
|
||||
if($update && ! $load) {
|
||||
|
||||
// only setup pagination on initial page view
|
||||
$pager_sql = '';
|
||||
|
||||
}
|
||||
else {
|
||||
$itemspage = get_pconfig(local_channel(), 'system', 'itemspage');
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
|
||||
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
|
||||
}
|
||||
$itemspage = get_pconfig(local_channel(), 'system', 'itemspage');
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
|
||||
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
|
||||
|
||||
// cmin and cmax are both -1 when the affinity tool is disabled
|
||||
|
||||
@@ -445,12 +408,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 = 'list';
|
||||
else
|
||||
$page_mode = 'client';
|
||||
$page_mode = 'client';
|
||||
|
||||
$parents_str = '';
|
||||
$blog_mode = feature_enabled(local_channel(), 'network_list_mode');
|
||||
if ($blog_mode) {
|
||||
$page_mode = 'list';
|
||||
}
|
||||
|
||||
// This fixes a very subtle bug so I'd better explain it. You wake up in the morning or return after a day
|
||||
// or three and look at your matrix page - after opening up your browser. The first page loads just as it
|
||||
@@ -472,33 +435,23 @@ 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 "
|
||||
);
|
||||
|
||||
$parents_str = ids_to_querystr($items, 'item_id');
|
||||
|
||||
require_once('include/items.php');
|
||||
|
||||
xchan_query($items);
|
||||
|
||||
$items = fetch_post_tags($items, true);
|
||||
}
|
||||
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 +480,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);
|
||||
|
||||
@@ -12,51 +12,72 @@ class Notifications extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
// ajax mark all unseen items read
|
||||
if(x($_REQUEST, 'markRead')) {
|
||||
if(isset($_REQUEST['markRead'])) {
|
||||
if (str_starts_with($_REQUEST['markRead'], 'forum_')) {
|
||||
$forum_id = substr($_REQUEST['markRead'], 6);
|
||||
|
||||
$abook = q("SELECT abook_xchan FROM abook WHERE abook_channel = %d AND abook_id = %d",
|
||||
intval(local_channel()),
|
||||
intval($forum_id)
|
||||
);
|
||||
|
||||
if ($abook) {
|
||||
q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND owner_xchan = '%s' AND item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1)",
|
||||
intval(local_channel()),
|
||||
dbesc($abook[0]['abook_xchan'])
|
||||
);
|
||||
}
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
switch($_REQUEST['markRead']) {
|
||||
case 'dm':
|
||||
$r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1 AND item_private = 2",
|
||||
q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1 AND item_private = 2",
|
||||
intval(local_channel())
|
||||
);
|
||||
break;
|
||||
case 'network':
|
||||
$r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1 AND item_private IN (0, 1)",
|
||||
q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1)",
|
||||
intval(local_channel())
|
||||
);
|
||||
break;
|
||||
case 'home':
|
||||
$r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1 AND item_wall = 1 AND item_private IN (0, 1)",
|
||||
q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1 AND item_wall = 1 AND item_private IN (0, 1)",
|
||||
intval(local_channel())
|
||||
);
|
||||
break;
|
||||
case 'all_events':
|
||||
$evdays = intval(get_pconfig(local_channel(), 'system', 'evdays', 3));
|
||||
$r = q("UPDATE event SET dismissed = 1 WHERE uid = %d AND dismissed = 0 AND dtstart < '%s' AND dtstart > '%s' ",
|
||||
q("UPDATE event SET dismissed = 1 WHERE uid = %d AND dismissed = 0 AND dtstart < '%s' AND dtstart > '%s' ",
|
||||
intval(local_channel()),
|
||||
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')),
|
||||
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
|
||||
);
|
||||
break;
|
||||
case 'notify':
|
||||
$r = q("UPDATE notify SET seen = 1 WHERE seen = 0 AND uid = %d",
|
||||
q("UPDATE notify SET seen = 1 WHERE seen = 0 AND uid = %d",
|
||||
intval(local_channel())
|
||||
);
|
||||
break;
|
||||
case 'pubs':
|
||||
unset($_SESSION['static_loadtime']);
|
||||
$_SESSION['sse_loadtime'] = datetime_convert();
|
||||
$_SESSION['static_loadtime'] = datetime_convert();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
// ajax mark all comments of a parent item read
|
||||
if(x($_REQUEST, 'markItemRead') && local_channel()) {
|
||||
if(isset($_REQUEST['markItemRead']) && local_channel()) {
|
||||
$r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND parent = %d",
|
||||
intval(local_channel()),
|
||||
intval($_REQUEST['markItemRead'])
|
||||
);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
@@ -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'] ?? '';
|
||||
|
||||
@@ -27,6 +27,8 @@ class Owa extends Controller {
|
||||
$this->error('Missing or invalid authorization header.');
|
||||
}
|
||||
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_REMOTE_USER'];
|
||||
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
|
||||
if ($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
|
||||
@@ -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.'));
|
||||
|
||||
@@ -759,7 +759,7 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
'$profile_id' => $r[0]['id'],
|
||||
'$profile_name' => array('profile_name', t('Profile name'), $r[0]['profile_name'], t('Required'), '*'),
|
||||
'$is_default' => $is_default,
|
||||
'$default' => t('This is your default profile.') . EOL . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))),
|
||||
'$default' => t('This is your default profile.') . ' ' . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))),
|
||||
'$advanced' => $advanced,
|
||||
'$name' => array('name', t('Your full name'), $r[0]['fullname'], t('Required'), '*'),
|
||||
'$pdesc' => array('pdesc', t('Short title/description'), $r[0]['pdesc'], t('Maximal 190 characters'), '', 'maxlength="190"'),
|
||||
@@ -841,7 +841,7 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
'$alt' => t('Profile Image'),
|
||||
'$profile_name' => $rr['profile_name'],
|
||||
'$visible' => (($rr['is_default'])
|
||||
? '<strong>' . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))) . '</strong>'
|
||||
? '<strong>' . escape_tags(translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile')))) . '</strong>'
|
||||
: '<a href="' . z_root() . '/profperm/' . $rr['id'] . '" />' . t('Edit visibility') . '</a>')
|
||||
));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -137,7 +137,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
|
||||
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
|
||||
'$search' => '',
|
||||
'$xchan' => '',
|
||||
'$order' => 'comment',
|
||||
'$order' => 'post',
|
||||
'$file' => '',
|
||||
'$cats' => '',
|
||||
'$tags' => (($hashtags) ? urlencode($hashtags) : ''),
|
||||
@@ -173,16 +173,15 @@ class Pubstream extends \Zotlabs\Web\Controller {
|
||||
$site_firehose_sql = " and owner_xchan in (select channel_hash from channel where channel_system = 0 and channel_removed = 0) ";
|
||||
}
|
||||
|
||||
if(Config::Get('system','public_list_mode'))
|
||||
$page_mode = 'list';
|
||||
else
|
||||
$page_mode = 'client';
|
||||
$page_mode = 'client';
|
||||
$blog_mode = Config::Get('system',' public_list_mode');
|
||||
|
||||
if ($blog_mode) {
|
||||
$page_mode = 'list';
|
||||
}
|
||||
|
||||
if(x($hashtags)) {
|
||||
$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 +195,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) {
|
||||
@@ -246,38 +245,20 @@ class Pubstream extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
// Then fetch all the children of the parents that are on this page
|
||||
$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, blog_mode: $blog_mode);
|
||||
|
||||
// use effective_uid param of xchan_query to help sort out comment permission
|
||||
// for sys_channel owned items.
|
||||
|
||||
xchan_query($items, true, local_channel());
|
||||
$items = fetch_post_tags($items,true);
|
||||
|
||||
if (!$hashtags) {
|
||||
$items = conv_sort($items, $ordering);
|
||||
}
|
||||
|
||||
|
||||
$items = conv_sort($items, $ordering);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$mode = (($hashtags) ? 'pubstream-new' : 'pubstream');
|
||||
|
||||
$o .= conversation($items,$mode,$update,$page_mode);
|
||||
$o .= conversation($items, 'pubstream', $update, $page_mode);
|
||||
|
||||
if($mid)
|
||||
$o .= '<div id="content-complete"></div>';
|
||||
|
||||
@@ -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 ",
|
||||
@@ -386,7 +386,7 @@ class Regate extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
else {
|
||||
zar_log('ZAR1135E not awaited url parameter received');
|
||||
goaway(z_root);
|
||||
goaway(z_root());
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -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
|
||||
]);
|
||||
|
||||
@@ -323,7 +323,6 @@ class Register extends Controller {
|
||||
$did2 = $email;
|
||||
$didx = 'e';
|
||||
|
||||
push_lang(($reg['lang']) ? $reg['lang'] : App::$language);
|
||||
$reonar['from'] = Config::Get('system', 'from_email');
|
||||
$reonar['to'] = $email;
|
||||
$reonar['subject'] = sprintf( t('Registration confirmation for %s'), Config::Get('system','sitename'));
|
||||
@@ -338,7 +337,6 @@ class Register extends Controller {
|
||||
'$hash' => $empin
|
||||
]
|
||||
);
|
||||
pop_lang();
|
||||
zar_reg_mail($reonar);
|
||||
|
||||
} else {
|
||||
@@ -445,7 +443,7 @@ class Register extends Controller {
|
||||
if(intval(Config::Get('system','register_policy')) == REGISTER_APPROVE) {
|
||||
$register_msg = ['register_msg', t('Why do you want to join this hub?'), ((x($_REQUEST,'register_msg')) ? $_REQUEST['register_msg'] : ''), t('This will help to review your registration')];
|
||||
$registration_is = t('Registration on this hub is by approval only.');
|
||||
$other_sites = '<a href="pubsites">' . t('Register at another affiliated hub in case when prefered') . '</a>';
|
||||
$other_sites = '<a href="pubsites">' . t('Register at another affiliated hub if preferred') . '</a>';
|
||||
}
|
||||
|
||||
$duty = zar_register_dutystate();
|
||||
|
||||
@@ -5,33 +5,33 @@ namespace Zotlabs\Module;
|
||||
class Removeaccount extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
|
||||
if($_SESSION['delegate'])
|
||||
return;
|
||||
|
||||
|
||||
if((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password']))))
|
||||
return;
|
||||
|
||||
|
||||
if((! x($_POST,'verify')) || (! strlen(trim($_POST['verify']))))
|
||||
return;
|
||||
|
||||
|
||||
if($_POST['verify'] !== $_SESSION['remove_account_verify'])
|
||||
return;
|
||||
|
||||
|
||||
|
||||
|
||||
$account = \App::get_account();
|
||||
$account_id = get_account_id();
|
||||
|
||||
|
||||
$x = account_verify_password($account['account_email'],$_POST['qxz_password']);
|
||||
if(! ($x && $x['account']))
|
||||
return;
|
||||
|
||||
|
||||
if($account['account_password_changed'] > NULL_DATE) {
|
||||
$d1 = datetime_convert('UTC','UTC','now - 48 hours');
|
||||
if($account['account_password_changed'] > d1) {
|
||||
if($account['account_password_changed'] > $d1) {
|
||||
notice( t('Account removals are not allowed within 48 hours of changing the account password.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
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(): void
|
||||
{
|
||||
$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 init() : void
|
||||
{
|
||||
|
||||
if (in_array($_GET['verb'], ['comment', 'load'])) {
|
||||
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,
|
||||
|
||||
@@ -71,7 +71,13 @@ class Search extends Controller {
|
||||
$url = unpack_link_id(basename($url));
|
||||
}
|
||||
|
||||
$f = Libzot::fetch_conversation(App::get_channel(), punify($url), true);
|
||||
$parsed = parse_url($url);
|
||||
if (isset($parsed['host'])) {
|
||||
$parsed['host'] = punify($parsed['host']);
|
||||
$url = unparse_url($parsed);
|
||||
}
|
||||
|
||||
$f = Libzot::fetch_conversation(App::get_channel(), $url, true);
|
||||
|
||||
if ($f) {
|
||||
$uuid = $f[0]['message_uuid'];
|
||||
@@ -87,7 +93,7 @@ class Search extends Controller {
|
||||
else {
|
||||
// try other fetch providers (e.g. diaspora, pubcrawl)
|
||||
$hookdata = [
|
||||
'url' => punify($url)
|
||||
'url' => $url
|
||||
];
|
||||
call_hooks('fetch_provider', $hookdata);
|
||||
}
|
||||
|
||||
@@ -153,14 +153,6 @@ class Channel {
|
||||
Master::Summon(['Directory', local_channel()]);
|
||||
Libsync::build_sync_packet();
|
||||
|
||||
$email_changed = false;
|
||||
if ($email_changed && App::$config['system']['register_policy'] == REGISTER_VERIFY) {
|
||||
|
||||
// FIXME - set to un-verified, blocked and redirect to logout
|
||||
// Q: Why? Are we verifying people or email addresses?
|
||||
// A: the policy is to verify email addresses
|
||||
}
|
||||
|
||||
goaway(z_root() . '/settings');
|
||||
return; // NOTREACHED
|
||||
}
|
||||
|
||||
@@ -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')),
|
||||
|
||||
@@ -504,12 +504,6 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
$this->check_add($checks, t('Generate ed25519 encryption keys'), $res, true, $help);
|
||||
|
||||
$res1 = extension_loaded('bcmath');
|
||||
$res2 = extension_loaded('gmp');
|
||||
if (! ($res1 || $res2)) {
|
||||
$help = t('Error: one of "bcmath" or "gmp" (bigmath library) extensions are required.') . EOL;
|
||||
}
|
||||
$this->check_add($checks, t('Bigmath library (either bcmath or gmp)'), $res1||$res2, $help);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -534,6 +528,7 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
$this->check_add($ck_funcs, t('xml PHP module'), true, true);
|
||||
$this->check_add($ck_funcs, t('zip PHP module'), true, true);
|
||||
$this->check_add($ck_funcs, t('intl PHP module'), true, true);
|
||||
$this->check_add($ck_funcs, t('gmp PHP module'), true, true);
|
||||
|
||||
if(function_exists('apache_get_modules')){
|
||||
if(! in_array('mod_rewrite', apache_get_modules())) {
|
||||
@@ -590,9 +585,15 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
$ck_funcs[6]['status'] = false;
|
||||
$ck_funcs[6]['help'] = t('Error: zip PHP module required but not installed.');
|
||||
}
|
||||
if(! extension_loaded('intl')) {
|
||||
$ck_funcs[6]['status'] = false;
|
||||
$ck_funcs[6]['help'] = t('Error: intl PHP module required but not installed.');
|
||||
|
||||
if (!extension_loaded('intl')) {
|
||||
$ck_funcs[7]['status'] = false;
|
||||
$ck_funcs[7]['help'] = t('Error: intl PHP module required but not installed.');
|
||||
}
|
||||
|
||||
if (!extension_loaded('gmp')) {
|
||||
$ck_funcs[8]['status'] = false;
|
||||
$ck_funcs[8]['help'] = t('Error: gmp PHP module required but not installed.');
|
||||
}
|
||||
|
||||
$checks = array_merge($checks, $ck_funcs);
|
||||
|
||||
@@ -20,6 +20,8 @@ class Sse_bs extends Controller {
|
||||
public static $limit;
|
||||
public static $offset;
|
||||
public static $xchans;
|
||||
public static $direction;
|
||||
public static $count_limit;
|
||||
|
||||
function init() {
|
||||
self::$uid = local_channel();
|
||||
@@ -41,8 +43,10 @@ class Sse_bs extends Controller {
|
||||
self::$limit = 30;
|
||||
self::$offset = 0;
|
||||
self::$xchans = '';
|
||||
self::$direction = get_pconfig(self::$uid, 'system', 'invert_notifications_order', false) ? 'ASC' : 'DESC';
|
||||
self::$count_limit = get_pconfig(self::$uid, 'system', 'notifications_count_limit', 100);
|
||||
|
||||
if (isset($_REQUEST['sse_rmids'])) {
|
||||
if (!empty($_REQUEST['sse_rmids'])) {
|
||||
self::mark_read(explode(',', $_REQUEST['sse_rmids']));
|
||||
}
|
||||
|
||||
@@ -64,7 +68,6 @@ class Sse_bs extends Controller {
|
||||
$_SESSION['sse_loadtime'] = datetime_convert();
|
||||
}
|
||||
|
||||
|
||||
$network = false;
|
||||
$dm = false;
|
||||
$home = false;
|
||||
@@ -91,8 +94,14 @@ class Sse_bs extends Controller {
|
||||
default:
|
||||
}
|
||||
|
||||
$selected_forum_id = null;
|
||||
if (str_starts_with(argv(1), 'forum_')) {
|
||||
$selected_forum_id = argv(1);
|
||||
$f = 'bs_forums';
|
||||
}
|
||||
|
||||
if(self::$offset && $f) {
|
||||
$result = self::$f(true);
|
||||
$result = self::$f($selected_forum_id ?? true);
|
||||
json_return_and_die($result);
|
||||
}
|
||||
|
||||
@@ -102,7 +111,7 @@ class Sse_bs extends Controller {
|
||||
self::bs_home($home),
|
||||
self::bs_notify(),
|
||||
self::bs_intros(),
|
||||
self::bs_forums(),
|
||||
self::bs_forums($selected_forum_id),
|
||||
self::bs_pubs($pubs),
|
||||
self::bs_files(),
|
||||
self::bs_all_events(),
|
||||
@@ -118,7 +127,6 @@ class Sse_bs extends Controller {
|
||||
}
|
||||
|
||||
function mark_read($arr) {
|
||||
|
||||
$mids = [];
|
||||
$str = '';
|
||||
$slice = 0;
|
||||
@@ -142,24 +150,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) {
|
||||
@@ -179,35 +214,39 @@ class Sse_bs extends Controller {
|
||||
|
||||
$limit = intval(self::$limit);
|
||||
$offset = self::$offset;
|
||||
$direction = self::$direction;
|
||||
$count_limit = intval(self::$count_limit);
|
||||
|
||||
$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, received DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY item.created $direction LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -234,7 +273,7 @@ class Sse_bs extends Controller {
|
||||
AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
|
||||
AND author_xchan != '%s'
|
||||
$item_normal
|
||||
$sql_extra LIMIT 100",
|
||||
$sql_extra LIMIT $count_limit",
|
||||
intval(self::$uid),
|
||||
dbesc(self::$ob_hash)
|
||||
);
|
||||
@@ -262,35 +301,39 @@ class Sse_bs extends Controller {
|
||||
|
||||
$limit = intval(self::$limit);
|
||||
$offset = self::$offset;
|
||||
$direction = self::$direction;
|
||||
$count_limit = intval(self::$count_limit);
|
||||
|
||||
$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
|
||||
ORDER BY created DESC, received DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY created $direction LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -316,7 +359,7 @@ class Sse_bs extends Controller {
|
||||
WHERE uid = %d and item_unseen = 1 AND item_private = 2
|
||||
$item_normal
|
||||
$sql_extra
|
||||
AND author_xchan != '%s' LIMIT 100",
|
||||
AND author_xchan != '%s' LIMIT $count_limit",
|
||||
intval(self::$uid),
|
||||
dbesc(self::$ob_hash)
|
||||
);
|
||||
@@ -344,36 +387,40 @@ class Sse_bs extends Controller {
|
||||
|
||||
$limit = intval(self::$limit);
|
||||
$offset = self::$offset;
|
||||
$direction = self::$direction;
|
||||
$count_limit = intval(self::$count_limit);
|
||||
|
||||
$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, received DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY item.created $direction LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -399,7 +446,7 @@ class Sse_bs extends Controller {
|
||||
WHERE uid = %d and item_unseen = 1 AND item_wall = 1 AND item_private IN (0, 1)
|
||||
$item_normal
|
||||
$sql_extra
|
||||
AND author_xchan != '%s' LIMIT 100",
|
||||
AND author_xchan != '%s' LIMIT $count_limit",
|
||||
intval(self::$uid),
|
||||
dbesc(self::$ob_hash)
|
||||
);
|
||||
@@ -438,53 +485,57 @@ class Sse_bs extends Controller {
|
||||
|
||||
$limit = intval(self::$limit);
|
||||
$offset = self::$offset;
|
||||
$direction = self::$direction;
|
||||
$count_limit = intval(self::$count_limit);
|
||||
|
||||
$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, received DESC LIMIT $limit OFFSET $offset",
|
||||
ORDER BY item.created $direction LIMIT $limit OFFSET $offset",
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbesc(self::$ob_hash),
|
||||
dbescdate($_SESSION['last_login_date'] ?? $_SESSION['static_loadtime'])
|
||||
dbescdate($_SESSION['static_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
);
|
||||
|
||||
if($items) {
|
||||
@@ -509,9 +560,9 @@ class Sse_bs extends Controller {
|
||||
$item_normal
|
||||
$sql_extra
|
||||
$sql_extra3
|
||||
AND author_xchan != '%s' LIMIT 100",
|
||||
AND author_xchan != '%s' LIMIT $count_limit",
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbescdate($_SESSION['last_login_date'] ?? $_SESSION['static_loadtime']),
|
||||
dbescdate($_SESSION['static_loadtime']),
|
||||
dbesc(self::$ob_hash)
|
||||
);
|
||||
|
||||
@@ -534,7 +585,9 @@ class Sse_bs extends Controller {
|
||||
if(! (self::$vnotify & VNOTIFY_SYSTEM))
|
||||
return $result;
|
||||
|
||||
$r = q("SELECT * FROM notify WHERE uid = %d AND seen = 0 ORDER BY created DESC",
|
||||
$direction = self::$direction;
|
||||
|
||||
$r = q("SELECT * FROM notify WHERE uid = %d AND seen = 0 ORDER BY created $direction",
|
||||
intval(self::$uid)
|
||||
);
|
||||
|
||||
@@ -561,7 +614,9 @@ class Sse_bs extends Controller {
|
||||
if(! (self::$vnotify & VNOTIFY_INTRO))
|
||||
return $result;
|
||||
|
||||
$r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ORDER BY abook_created DESC LIMIT 50",
|
||||
$direction = self::$direction;
|
||||
|
||||
$r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ORDER BY abook_created $direction LIMIT 50",
|
||||
intval(self::$uid)
|
||||
);
|
||||
|
||||
@@ -576,79 +631,95 @@ class Sse_bs extends Controller {
|
||||
|
||||
}
|
||||
|
||||
function bs_forums() {
|
||||
|
||||
$result['forums']['notifications'] = [];
|
||||
$result['forums']['count'] = 0;
|
||||
$result['forums']['offset'] = -1;
|
||||
|
||||
if(! self::$uid)
|
||||
return $result;
|
||||
|
||||
if(! (self::$vnotify & VNOTIFY_FORUMS))
|
||||
return $result;
|
||||
|
||||
function bs_forums($selected_forum_id) {
|
||||
$forums = get_forum_channels(self::$uid);
|
||||
|
||||
if(!self::$uid || !(self::$vnotify & VNOTIFY_FORUMS) || !$forums) {
|
||||
$result['forum']['notifications'] = [];
|
||||
$result['forum']['count'] = 0;
|
||||
$result['forum']['offset'] = -1;
|
||||
return $result;
|
||||
}
|
||||
|
||||
if($forums) {
|
||||
$item_normal = item_normal();
|
||||
$p_sql = '';
|
||||
|
||||
$sql_extra = '';
|
||||
if(! (self::$vnotify & VNOTIFY_LIKE))
|
||||
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
|
||||
$fcount = count($forums);
|
||||
$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 )" : '');
|
||||
*/
|
||||
$forum_id = 'forum_' . $forums[$x]['abook_id'];
|
||||
|
||||
$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",
|
||||
$result[$forum_id]['notifications'] = [];
|
||||
$result[$forum_id]['count'] = 0;
|
||||
|
||||
$limit = intval(self::$limit);
|
||||
$offset = self::$offset;
|
||||
$direction = self::$direction;
|
||||
$count_limit = intval(self::$count_limit);
|
||||
|
||||
$sql_extra = '';
|
||||
if (!(self::$vnotify & VNOTIFY_LIKE)) {
|
||||
$sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
elseif (!feature_enabled(self::$uid, 'dislike')) {
|
||||
$sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
|
||||
}
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
// Filter internal follow activities and strerams add/remove activities
|
||||
$item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
|
||||
|
||||
if ($forum_id === $selected_forum_id) {
|
||||
$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.owner_xchan = '%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
|
||||
ORDER BY item.created $direction LIMIT $limit OFFSET $offset",
|
||||
intval(self::$uid),
|
||||
dbescdate($_SESSION['sse_loadtime']),
|
||||
dbescdate($forums[$x]['xchan_hash']),
|
||||
dbesc(self::$ob_hash)
|
||||
);
|
||||
|
||||
if ($items) {
|
||||
$result[$forum_id]['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
|
||||
xchan_query($items);
|
||||
foreach($items as $item) {
|
||||
$parsed = Enotify::format($item);
|
||||
if($parsed) {
|
||||
$result[$forum_id]['notifications'][] = $parsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$result[$forum_id]['offset'] = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$r = q("SELECT id FROM item
|
||||
WHERE uid = %d 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'
|
||||
AND item.owner_xchan = '%s'
|
||||
$item_normal
|
||||
$sql_extra LIMIT $count_limit",
|
||||
intval(self::$uid),
|
||||
dbesc($forums[$x]['xchan_hash']),
|
||||
dbesc(self::$ob_hash),
|
||||
dbesc($forums[$x]['xchan_hash'])
|
||||
);
|
||||
|
||||
|
||||
if($r[0]['total']) {
|
||||
|
||||
$forums[$x]['notify_link'] = z_root() . '/network/?f=&pf=1&unseen=1&cid=' . $forums[$x]['abook_id'];
|
||||
$forums[$x]['name'] = $forums[$x]['xchan_name'];
|
||||
$forums[$x]['addr'] = $forums[$x]['xchan_addr'] ?? $forums[$x]['xchan_url'];
|
||||
$forums[$x]['url'] = $forums[$x]['xchan_url'];
|
||||
$forums[$x]['photo'] = $forums[$x]['xchan_photo_s'];
|
||||
$forums[$x]['unseen'] = $r[0]['total'];
|
||||
$forums[$x]['private_forum'] = ((isset($forums[$x]['private_forum']) && $forums[$x]['private_forum']) ? 'lock' : '');
|
||||
$forums[$x]['message'] = ((isset($forums[$x]['private_forum']) && $forums[$x]['private_forum']) ? t('Private forum') : t('Public forum'));
|
||||
|
||||
unset($forums[$x]['abook_id']);
|
||||
unset($forums[$x]['xchan_hash']);
|
||||
unset($forums[$x]['xchan_name']);
|
||||
unset($forums[$x]['xchan_url']);
|
||||
unset($forums[$x]['xchan_photo_s']);
|
||||
|
||||
$i = $i + $r[0]['total'];
|
||||
|
||||
}
|
||||
else {
|
||||
unset($forums[$x]);
|
||||
if ($r) {
|
||||
$result[$forum_id]['count'] = count($r);
|
||||
}
|
||||
}
|
||||
|
||||
$result['forums']['count'] = $i;
|
||||
$result['forums']['notifications'] = array_values($forums);
|
||||
|
||||
}
|
||||
|
||||
return $result;
|
||||
@@ -667,6 +738,7 @@ class Sse_bs extends Controller {
|
||||
if(! (self::$vnotify & VNOTIFY_FILES))
|
||||
return $result;
|
||||
|
||||
$direction = self::$direction;
|
||||
$item_normal = item_normal();
|
||||
|
||||
// Filter internal follow activities and strerams add/remove activities
|
||||
@@ -679,7 +751,7 @@ class Sse_bs extends Controller {
|
||||
AND author_xchan != '%s'
|
||||
AND item_unseen = 1
|
||||
$item_normal
|
||||
ORDER BY created DESC, received DESC",
|
||||
ORDER BY created $direction",
|
||||
dbesc(ACTIVITY_POST),
|
||||
intval(self::$uid),
|
||||
dbesc(self::$ob_hash)
|
||||
@@ -711,10 +783,12 @@ class Sse_bs extends Controller {
|
||||
if(! (self::$vnotify & VNOTIFY_EVENT))
|
||||
return $result;
|
||||
|
||||
$direction = self::$direction;
|
||||
|
||||
$r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash
|
||||
WHERE event.uid = %d AND dtstart < '%s' AND dtstart > '%s' and dismissed = 0
|
||||
and etype in ( 'event', 'birthday' )
|
||||
ORDER BY dtstart DESC",
|
||||
ORDER BY dtstart $direction",
|
||||
intval(self::$uid),
|
||||
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval(self::$evdays) . ' days')),
|
||||
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -20,27 +20,35 @@ class Vote extends Controller {
|
||||
json_return_and_die($ret);
|
||||
}
|
||||
|
||||
|
||||
$fetch = null;
|
||||
$id = argv(1);
|
||||
$response = $_REQUEST['answer'];
|
||||
|
||||
if ($id) {
|
||||
$fetch = q("select * from item where id = %d limit 1",
|
||||
intval($id)
|
||||
);
|
||||
if (!$id) {
|
||||
$ret['message'] = t('Missing poll id.');
|
||||
json_return_and_die($ret);
|
||||
}
|
||||
|
||||
$answer = q("select * from item where parent = %d and uid = %d and obj_type = 'Answer' limit 1",
|
||||
intval($id),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
if ($fetch && $fetch[0]['obj_type'] === 'Question') {
|
||||
$obj = json_decode($fetch[0]['obj'],true);
|
||||
|
||||
if ($answer) {
|
||||
$ret['message'] = t('You have already submitted your vote for this poll.');
|
||||
json_return_and_die($ret);
|
||||
}
|
||||
else {
|
||||
|
||||
$poll = q("select * from item where id = %d limit 1",
|
||||
intval($id)
|
||||
);
|
||||
|
||||
if (!$poll && $poll[0]['obj_type'] !== 'Question') {
|
||||
$ret['message'] = t('Poll not found.');
|
||||
json_return_and_die($ret);
|
||||
}
|
||||
|
||||
$response = $_REQUEST['answer'];
|
||||
$obj = json_decode($poll[0]['obj'],true);
|
||||
|
||||
$valid = false;
|
||||
|
||||
if ($obj['oneOf']) {
|
||||
@@ -81,17 +89,18 @@ class Vote extends Controller {
|
||||
$item['aid'] = $channel['channel_account_id'];
|
||||
$item['uid'] = $channel['channel_id'];
|
||||
$item['item_origin'] = 1;
|
||||
$item['parent'] = $fetch[0]['id'];
|
||||
$item['parent_mid'] = $fetch[0]['mid'];
|
||||
$item['thr_parent'] = $fetch[0]['mid'];
|
||||
$item['parent'] = $poll[0]['id'];
|
||||
$item['parent_mid'] = $poll[0]['mid'];
|
||||
$item['thr_parent'] = $poll[0]['mid'];
|
||||
$item['uuid'] = new_uuid();
|
||||
$item['mid'] = z_root() . '/item/' . $item['uuid'];
|
||||
$item['verb'] = 'Create';
|
||||
$item['title'] = $res;
|
||||
$item['author_xchan'] = $channel['channel_hash'];
|
||||
$item['owner_xchan'] = $fetch[0]['author_xchan'];
|
||||
$item['allow_cid'] = '<' . $fetch[0]['author_xchan'] . '>';
|
||||
$item['owner_xchan'] = $poll[0]['author_xchan'];
|
||||
$item['allow_cid'] = '<' . $poll[0]['author_xchan'] . '>';
|
||||
$item['item_private'] = 1;
|
||||
$item['item_unseen'] = 0;
|
||||
$item['obj_type'] = 'Note';
|
||||
$item['author'] = channelx_by_n($channel['channel_id']);
|
||||
$item['obj'] = Activity::encode_item($item);
|
||||
@@ -104,7 +113,7 @@ class Vote extends Controller {
|
||||
|
||||
$x = item_store($item);
|
||||
|
||||
retain_item($fetch[0]['id']);
|
||||
retain_item($poll[0]['id']);
|
||||
|
||||
if($x['success']) {
|
||||
Master::Summon(['Notifier', 'like', $x['item_id']]);
|
||||
@@ -125,7 +134,7 @@ class Vote extends Controller {
|
||||
}
|
||||
|
||||
$ret['success'] = true;
|
||||
$ret['message'] = t('Response submitted. Updates may not appear instantly.');
|
||||
$ret['message'] = t('Your vote has been submitted. Updates may not appear instantly.');
|
||||
json_return_and_die($ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,6 +9,10 @@ class Zot_probe extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
if (!local_channel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$addr = $_GET['addr'] ?? '';
|
||||
|
||||
$o = '<h3>Zot6 Probe Diagnostic</h3>';
|
||||
|
||||
49
Zotlabs/Photo/ImageQuality.php
Normal file
49
Zotlabs/Photo/ImageQuality.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Photo;
|
||||
|
||||
/**
|
||||
* A class to represent image quality values.
|
||||
*/
|
||||
class ImageQuality
|
||||
{
|
||||
readonly string $mimeType;
|
||||
readonly int $value;
|
||||
|
||||
private const DEFAULT_VALUE = [
|
||||
'image/jpeg' => JPEG_QUALITY,
|
||||
'image/png' => PNG_QUALITY,
|
||||
'image/avif' => AVIF_QUALITY,
|
||||
'image/webp' => WEBP_QUALITY,
|
||||
];
|
||||
|
||||
public function __construct(string $mimeType, int $value) {
|
||||
[ $min, $max ] = $this->validRange($mimeType);
|
||||
|
||||
if ($value < $min || $value > $max) {
|
||||
$value = self::DEFAULT_VALUE[$mimeType];
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
$this->mimeType = $mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the valid quality setting range for the given mime type.
|
||||
*
|
||||
* @param string $mimeType The mime type whose range to return.
|
||||
*
|
||||
* @return The valid range as an array with two elements as
|
||||
* [ $min, $max ].
|
||||
*/
|
||||
public static function validRange(string $mimeType): array {
|
||||
// Max quality for PNG is 10, for all others it's 100.
|
||||
return $mimeType === 'image/png' ? [ 0, 10 ] : [ 1, 100 ];
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ class PhotoGd extends PhotoDriver {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see \Zotlabs\Photo\PhotoDriver::supportedTypes()
|
||||
*/
|
||||
public function supportedTypes() {
|
||||
@@ -25,16 +26,21 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter
|
||||
*/
|
||||
protected function load($data, $type) {
|
||||
$this->valid = false;
|
||||
if(! $data)
|
||||
return;
|
||||
|
||||
$this->image = @imagecreatefromstring($data);
|
||||
$this->image = imagecreatefromstring($data);
|
||||
if($this->image !== false) {
|
||||
$this->valid = true;
|
||||
$this->setDimensions();
|
||||
@@ -145,6 +151,7 @@ class PhotoGd extends PhotoDriver {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see \Zotlabs\Photo\PhotoDriver::imageString()
|
||||
*/
|
||||
public function imageString() {
|
||||
@@ -152,52 +159,30 @@ class PhotoGd extends PhotoDriver {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$quality = false;
|
||||
|
||||
ob_start();
|
||||
|
||||
switch($this->getType()){
|
||||
|
||||
case 'image/avif':
|
||||
imageavif($this->image, null, $this->getQuality()->value);
|
||||
break;
|
||||
|
||||
case 'image/png':
|
||||
$quality = Config::Get('system', 'png_quality');
|
||||
|
||||
if((! $quality) || ($quality > 9)) {
|
||||
$quality = PNG_QUALITY;
|
||||
}
|
||||
|
||||
if (function_exists('imagepng')) {
|
||||
\imagepng($this->image, NULL, $quality);
|
||||
}
|
||||
|
||||
imagepng($this->image, null, $this->getQuality()->value);
|
||||
break;
|
||||
|
||||
case 'image/webp':
|
||||
$quality = Config::Get('system', 'webp_quality');
|
||||
imagewebp($this->image, null, $this->getQuality()->value);
|
||||
break;
|
||||
|
||||
if((! $quality) || ($quality > 100)) {
|
||||
$quality = WEBP_QUALITY;
|
||||
}
|
||||
case 'image/gif':
|
||||
imagegif($this->image);
|
||||
break;
|
||||
|
||||
if (function_exists('imagewebp')) {
|
||||
\imagewebp($this->image, NULL, $quality);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'image/jpeg':
|
||||
// gd can lack imagejpeg(), but we verify during installation it is available
|
||||
|
||||
case 'image/jpeg':
|
||||
default:
|
||||
$quality = Config::Get('system', 'jpeg_quality');
|
||||
|
||||
if((! $quality) || ($quality > 100)) {
|
||||
$quality = JPEG_QUALITY;
|
||||
}
|
||||
|
||||
if (function_exists('imagejpeg')) {
|
||||
\imagejpeg($this->image, NULL, $quality);
|
||||
}
|
||||
|
||||
imagejpeg($this->image, null, $this->getQuality()->value);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -207,4 +192,23 @@ class PhotoGd extends PhotoDriver {
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default image quality for the given mime type.
|
||||
*
|
||||
* If the setting has been overridden in the database, we use that value,
|
||||
* otherwise the hardcoded defaults.
|
||||
*
|
||||
* @return ImageQuality The image quality value for the current mime type.
|
||||
*/
|
||||
private function getQuality(): ImageQuality {
|
||||
$key = match($this->getType()) {
|
||||
'image/avif' => 'avif_quality',
|
||||
'image/jpeg' => 'jpeg_quality',
|
||||
'image/png' => 'png_quality',
|
||||
'image/webp' => 'webp_quality',
|
||||
};
|
||||
|
||||
return new ImageQuality($this->getType(), Config::Get('system', $key));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ 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/');
|
||||
|
||||
@@ -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.
|
||||
@@ -43,7 +44,7 @@ class Browser extends DAV\Browser\Plugin {
|
||||
*/
|
||||
public function __construct(&$auth) {
|
||||
$this->auth = $auth;
|
||||
parent::__construct(true, false);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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;
|
||||
|
||||
@@ -866,7 +866,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
||||
$path = $path . '/' . $r[0]['filename'];
|
||||
}
|
||||
if (! $r) {
|
||||
$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
|
||||
$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, is_photo, os_storage, created, edited from attach
|
||||
where folder = '%s' and filename = '%s' and uid = %d $perms order by filename limit 1",
|
||||
dbesc($folder),
|
||||
dbesc(basename($file)),
|
||||
@@ -875,7 +875,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
||||
}
|
||||
if (! $r) {
|
||||
$errors = true;
|
||||
$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
|
||||
$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, is_photo, os_storage, created, edited from attach
|
||||
where folder = '%s' and filename = '%s' and uid = %d order by filename limit 1",
|
||||
dbesc($folder),
|
||||
dbesc(basename($file)),
|
||||
|
||||
@@ -93,19 +93,20 @@ class File extends DAV\Node implements DAV\IFile {
|
||||
|
||||
$x = attach_syspaths($this->auth->owner_id,$this->data['hash']);
|
||||
|
||||
$y = q("update attach set display_path = '%s where hash = '%s' and uid = %d",
|
||||
$y = q("update attach set display_path = '%s' where hash = '%s' and uid = %d",
|
||||
dbesc($x['path']),
|
||||
dbesc($this->data['hash']),
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
|
||||
if($this->data->is_photo) {
|
||||
if($this->data['is_photo']) {
|
||||
$r = q("update photo set filename = '%s', display_path = '%s' where resource_id = '%s' and uid = %d",
|
||||
dbesc($newName),
|
||||
dbesc($x['path']),
|
||||
dbesc($this->data['hash']),
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$ch = channelx_by_n($this->auth->owner_id);
|
||||
|
||||
29
Zotlabs/Update/_1264.php
Normal file
29
Zotlabs/Update/_1264.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class _1264 {
|
||||
|
||||
function run() {
|
||||
|
||||
dbq("START TRANSACTION");
|
||||
|
||||
$admin_email = trim(Config::Get('system','admin_email'));
|
||||
|
||||
$r = q("UPDATE account SET account_roles = 0 WHERE account_created > '2025-06-24 00:00:00' AND account_email <> '%s'",
|
||||
dbesc($admin_email)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
dbq("COMMIT");
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
|
||||
dbq("ROLLBACK");
|
||||
return UPDATE_FAILED;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,63 @@ 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);
|
||||
if (!$keyInfo) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$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';
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
namespace Zotlabs\Widget;
|
||||
|
||||
use App;
|
||||
|
||||
class Archive {
|
||||
|
||||
@@ -15,37 +16,40 @@ class Archive {
|
||||
|
||||
$o = '';
|
||||
|
||||
if(! \App::$profile_uid) {
|
||||
if (!App::$profile) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$uid = \App::$profile_uid;
|
||||
$uid = App::$profile['profile_uid'];
|
||||
|
||||
if(! feature_enabled($uid,'archives'))
|
||||
if (!feature_enabled($uid, 'archives')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if(! perm_is_allowed($uid,get_observer_hash(),'view_stream'))
|
||||
if (!perm_is_allowed($uid,get_observer_hash(),'view_stream')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$wall = ((array_key_exists('wall', $arr)) ? intval($arr['wall']) : 0);
|
||||
$wall = ((array_key_exists('articles', $arr)) ? 2 : $wall);
|
||||
|
||||
$style = ((array_key_exists('style', $arr)) ? $arr['style'] : 'select');
|
||||
$showend = ((get_pconfig($uid,'system','archive_show_end_date')) ? true : false);
|
||||
$mindate = get_pconfig($uid,'system','archive_mindate');
|
||||
$visible_years = get_pconfig($uid,'system','archive_visible_years',5);
|
||||
$showend = ((get_pconfig($uid, 'system', 'archive_show_end_date')) ? true : false);
|
||||
$mindate = get_pconfig($uid, 'system', 'archive_mindate');
|
||||
$visible_years = get_pconfig($uid, 'system', 'archive_visible_years', 5);
|
||||
|
||||
$url = z_root() . '/' . \App::$cmd;
|
||||
$url = z_root() . '/' . App::$module . '/' . App::$profile['channel_address'];
|
||||
|
||||
$ret = list_post_dates($uid,$wall,$mindate);
|
||||
|
||||
if(! count($ret))
|
||||
if (empty($ret)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$cutoff_year = intval(datetime_convert('',date_default_timezone_get(),'now','Y')) - $visible_years;
|
||||
$cutoff = ((array_key_exists($cutoff_year,$ret))? true : false);
|
||||
$cutoff = ((array_key_exists($cutoff_year,$ret)) ? true : false);
|
||||
|
||||
$o = replace_macros(get_markup_template('posted_date_widget.tpl'),array(
|
||||
return replace_macros(get_markup_template('posted_date_widget.tpl'), [
|
||||
'$title' => t('Archives'),
|
||||
'$size' => $visible_years,
|
||||
'$cutoff_year' => $cutoff_year,
|
||||
@@ -54,8 +58,8 @@ class Archive {
|
||||
'$style' => $style,
|
||||
'$showend' => $showend,
|
||||
'$dates' => $ret
|
||||
));
|
||||
return $o;
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
];
|
||||
|
||||
|
||||
@@ -21,14 +21,25 @@ class Helpindex {
|
||||
$this->determine_help_language();
|
||||
$this->find_help_file('toc', $this->lang['language']);
|
||||
|
||||
if (! empty($this->file_name)) {
|
||||
$this->contents = translate_projectname(
|
||||
file_get_contents($this->file_name)
|
||||
);
|
||||
}
|
||||
$sections = [];
|
||||
$this->contents = '';
|
||||
|
||||
$tpl = get_markup_template('widget.tpl');
|
||||
return replace_macros($tpl, [ '$widget' => $this ]);
|
||||
if (!empty($this->file_name) && is_readable($this->file_name)) {
|
||||
$json = file_get_contents($this->file_name);
|
||||
$this->contents = translate_projectname($json);
|
||||
|
||||
$decoded = json_decode($json, true);
|
||||
if (is_array($decoded)) {
|
||||
$sections = $decoded;
|
||||
}
|
||||
}
|
||||
$tpl = get_markup_template('help-index.tpl');
|
||||
|
||||
return replace_macros($tpl, [
|
||||
'$title' => t('Documentation Index'),
|
||||
'$sections' => $sections,
|
||||
'$contents' => $this->contents
|
||||
]);
|
||||
}
|
||||
|
||||
public function title(): string {
|
||||
|
||||
@@ -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 ';
|
||||
@@ -305,11 +309,13 @@ class Messages {
|
||||
$author_sql = '';
|
||||
|
||||
if($author_url) {
|
||||
$author_sql = " AND url = '" . protect_sprintf(dbesc($author_url)) . "' ";
|
||||
$author_sql = " AND notify.url = '" . protect_sprintf(dbesc($author_url)) . "' ";
|
||||
}
|
||||
|
||||
$notices = q("SELECT * FROM notify WHERE uid = %d $author_sql
|
||||
ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
$notices = q("SELECT notify.*, xchan.xchan_addr FROM notify
|
||||
LEFT JOIN xchan ON notify.url = xchan.xchan_url
|
||||
WHERE uid = %d $author_sql
|
||||
GROUP BY notify.id ORDER BY created DESC LIMIT $limit OFFSET $offset",
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
@@ -325,7 +331,7 @@ class Messages {
|
||||
}
|
||||
|
||||
$entries[$i]['author_name'] = $notice['xname'];
|
||||
$entries[$i]['author_addr'] = $notice['url'];
|
||||
$entries[$i]['author_addr'] = $notice['xchan_addr'];
|
||||
$entries[$i]['author_img'] = $notice['photo'];// $item['author']['xchan_photo_s'];
|
||||
$entries[$i]['info'] = '';
|
||||
$entries[$i]['created'] = datetime_convert('UTC', date_default_timezone_get(), $notice['created']);
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
|
||||
namespace Zotlabs\Widget;
|
||||
|
||||
use App;
|
||||
|
||||
class Notifications {
|
||||
|
||||
function widget($arr) {
|
||||
|
||||
$channel = \App::get_channel();
|
||||
$notifications = [];
|
||||
|
||||
if(local_channel()) {
|
||||
@@ -21,36 +22,36 @@ 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 seen')
|
||||
],
|
||||
'filter' => [
|
||||
'posts_label' => t('Show new posts only'),
|
||||
'posts_label' => t('Conversation starters'),
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
$channel = App::get_channel();
|
||||
$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 +60,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 seen')
|
||||
],
|
||||
'filter' => [
|
||||
'posts_label' => t('Show new posts only'),
|
||||
'posts_label' => t('Conversation starters'),
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
];
|
||||
@@ -79,13 +80,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 +95,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,34 +107,46 @@ 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')
|
||||
]
|
||||
];
|
||||
|
||||
$notifications[] = [
|
||||
'type' => 'forums',
|
||||
'icon' => 'chat-quote',
|
||||
'severity' => 'secondary',
|
||||
'label' => t('Forums'),
|
||||
'title' => t('Forums'),
|
||||
'filter' => [
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
];
|
||||
$forums = get_forum_channels(local_channel());
|
||||
foreach($forums as $forum) {
|
||||
$notifications[] = [
|
||||
'type' => 'forum_' . $forum['abook_id'],
|
||||
'icon' => 'chat-quote',
|
||||
'severity' => 'secondary',
|
||||
'label' => $forum['xchan_name'],
|
||||
'title' => t('Unseen forum activity'),
|
||||
'filter' => [
|
||||
'posts_label' => t('Conversation starters'),
|
||||
'name_label' => t('Filter by name or address')
|
||||
],
|
||||
'viewall' => [
|
||||
'url' => 'network?pf=1&cid=' . $forum['abook_id'],
|
||||
'label' => t('View all')
|
||||
],
|
||||
'markall' => [
|
||||
'label' => t('Mark all seen')
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(local_channel() && is_site_admin()) {
|
||||
@@ -142,7 +155,7 @@ class Notifications {
|
||||
'icon' => 'person-exclamation',
|
||||
'severity' => 'danger',
|
||||
'label' => t('Registrations'),
|
||||
'title' => t('New registrations notifications'),
|
||||
'title' => t('Unseen registration activity'),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -152,33 +165,30 @@ 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')
|
||||
],
|
||||
/*
|
||||
'markall' => [
|
||||
'label' => t('Mark all notifications seen')
|
||||
],
|
||||
*/
|
||||
'filter' => [
|
||||
'posts_label' => t('Show new posts only'),
|
||||
'posts_label' => t('Conversation starters'),
|
||||
'name_label' => t('Filter by name or address')
|
||||
]
|
||||
],
|
||||
'markall' => [
|
||||
'label' => t('Mark all seen')
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$o = replace_macros(get_markup_template('notifications_widget.tpl'), [
|
||||
return replace_macros(get_markup_template('notifications_widget.tpl'), [
|
||||
'$notifications' => $notifications,
|
||||
'$no_notifications' => t('Sorry, you have got no notifications at the moment'),
|
||||
'$loading' => t('Loading'),
|
||||
'$sys_only' => empty($arr['sys_only']) ? 0 : 1
|
||||
|
||||
'$sys_only' => empty($arr['sys_only']) ? 0 : 1,
|
||||
'$invert_notifications_order' => get_pconfig(local_channel(), 'system', 'invert_notifications_order', false),
|
||||
'$count_limit' => get_pconfig(local_channel(), 'system', 'notifications_count_limit', 100)
|
||||
]);
|
||||
|
||||
return $o;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
427
boot.php
427
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,10 +70,10 @@ require_once('include/security.php');
|
||||
|
||||
|
||||
define('PLATFORM_NAME', 'hubzilla');
|
||||
define('STD_VERSION', '10.2');
|
||||
define('STD_VERSION', '10.6');
|
||||
define('ZOT_REVISION', '6.0');
|
||||
|
||||
define('DB_UPDATE_VERSION', 1263);
|
||||
define('DB_UPDATE_VERSION', 1264);
|
||||
|
||||
define('PROJECT_BASE', __DIR__);
|
||||
|
||||
@@ -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,10 +657,12 @@ 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())) {
|
||||
if (isset($default_timezone)) {
|
||||
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(),
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"ext-json": "*",
|
||||
"ext-posix": "*",
|
||||
"ext-sodium": "*",
|
||||
"ext-bcmath": "*",
|
||||
"ext-gmp": "*",
|
||||
"sabre/dav": "^4.0",
|
||||
"michelf/php-markdown": "^2.0",
|
||||
"bshaffer/oauth2-server-php": "^1.9",
|
||||
@@ -41,22 +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": "^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",
|
||||
"twbs/bootstrap-icons": "^1.11"
|
||||
"scssphp/scssphp": "^2.0.1",
|
||||
"twbs/bootstrap-icons": "^1.11",
|
||||
"macgirvin/http-message-signer": "^0.2.6",
|
||||
"root23/php-json-canonicalization": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-yaml": "*",
|
||||
|
||||
2224
composer.lock
generated
2224
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)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user