mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-24 18:19:12 -04:00
Compare commits
877 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e80de634d3 | ||
|
|
536f80e50b | ||
|
|
3eeb173efd | ||
|
|
e90fc6d714 | ||
|
|
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 | ||
|
|
bbcf7e9aa1 | ||
|
|
45a2ebc662 | ||
|
|
aece22aee6 | ||
|
|
9904eba277 | ||
|
|
7c0f98a513 | ||
|
|
8d25b6eae4 | ||
|
|
9369085835 | ||
|
|
059113d2a8 | ||
|
|
f60dff788e | ||
|
|
9c20b4809a | ||
|
|
00b3039b6e | ||
|
|
2695094d16 | ||
|
|
bcfdb73001 | ||
|
|
1650809cd8 | ||
|
|
991815469f | ||
|
|
c5fb8eafac | ||
|
|
a0c98e070e | ||
|
|
7d6202be13 | ||
|
|
4ba470318c | ||
|
|
e948aaf751 | ||
|
|
3789017ca0 | ||
|
|
48f5acced3 | ||
|
|
13e2d2f654 | ||
|
|
8d45fd36a1 | ||
|
|
6ed2301a94 | ||
|
|
a0eb701503 | ||
|
|
39f9a38b23 | ||
|
|
590c0ea778 | ||
|
|
f36d8e4bd2 | ||
|
|
4e3bec8a35 | ||
|
|
eec918bf4a | ||
|
|
13002af4c3 | ||
|
|
40c63a7f12 | ||
|
|
3d0621eb8c | ||
|
|
030c02dfdc | ||
|
|
00c1509549 | ||
|
|
8122c40252 | ||
|
|
787c63b7ae | ||
|
|
ee988edc83 | ||
|
|
a71f5e123a | ||
|
|
7579749adc | ||
|
|
cf408c3fac | ||
|
|
0c97792ca7 | ||
|
|
84d63b3b67 | ||
|
|
63aa50eb8d | ||
|
|
7fb13f23fe | ||
|
|
65156a0e4d | ||
|
|
e3eebcd95d | ||
|
|
9eff1a08d4 | ||
|
|
cfcac590c3 | ||
|
|
872415bffe | ||
|
|
a46b781664 | ||
|
|
b77fac43c8 | ||
|
|
2b4b409c01 | ||
|
|
67aa547c48 | ||
|
|
e288f33776 | ||
|
|
a5aab4c30e | ||
|
|
cf7613b3e0 | ||
|
|
fa01a2b348 | ||
|
|
65c8de3410 | ||
|
|
d9b262348f | ||
|
|
ea9d2a0acf | ||
|
|
5d55006be8 | ||
|
|
d9ced0c6bf | ||
|
|
8d4d1b17c7 | ||
|
|
453f6a08a3 | ||
|
|
b6560e5456 | ||
|
|
b805f48c32 | ||
|
|
33b78a4943 | ||
|
|
48b187ccd8 | ||
|
|
f680bba3e6 | ||
|
|
09aabc6b41 | ||
|
|
0dd456c653 | ||
|
|
97ba14cbe0 | ||
|
|
ee6367a549 | ||
|
|
fc52d1b44f | ||
|
|
bfce562a46 | ||
|
|
8d8a7f44e1 | ||
|
|
6c8da6ce36 | ||
|
|
e19a050b92 | ||
|
|
a13bf6a3fe | ||
|
|
0edf761499 | ||
|
|
bf76d5981f | ||
|
|
33fcb43173 | ||
|
|
ffae47f523 | ||
|
|
c07cdb30fa | ||
|
|
546c4fcad2 | ||
|
|
0a17b83578 | ||
|
|
2782b6d724 | ||
|
|
dc076a4c00 | ||
|
|
a550c7c853 | ||
|
|
7a3d59bff3 | ||
|
|
82a3b71a51 | ||
|
|
e39b2eb7b9 | ||
|
|
9f8248cc9c | ||
|
|
71e4326606 | ||
|
|
7eb6f9b11d | ||
|
|
4625ffa6b4 | ||
|
|
3e6a646603 | ||
|
|
324b281813 | ||
|
|
03d1f3383e | ||
|
|
69a23c604d | ||
|
|
174469970a | ||
|
|
89b254dc1c | ||
|
|
8e51988e96 | ||
|
|
52e279f443 | ||
|
|
4efa853690 | ||
|
|
9b13055dfe | ||
|
|
06afd8a375 | ||
|
|
6f027544d6 | ||
|
|
2d2c9fa519 | ||
|
|
27efb887d2 | ||
|
|
ccd52584a4 | ||
|
|
ab0fdb13d4 | ||
|
|
2bca44ed25 | ||
|
|
eab08d0bcb | ||
|
|
d3f00704bd | ||
|
|
1e1a7109a9 | ||
|
|
ebab5ff281 | ||
|
|
0165f44063 | ||
|
|
5fb6e5d6f7 | ||
|
|
8fc0e41beb | ||
|
|
3ad63a6e82 | ||
|
|
5a84ffdcda | ||
|
|
ad993645be | ||
|
|
392cb020aa | ||
|
|
0701cde239 | ||
|
|
a136c288d5 | ||
|
|
884b612ffc | ||
|
|
ae0d138d2a | ||
|
|
1624a2620a | ||
|
|
48ef4744ac | ||
|
|
a17cb75baf | ||
|
|
f4769d0f04 | ||
|
|
c8e30a00e2 | ||
|
|
169c971cb1 | ||
|
|
51745d3652 | ||
|
|
3ebbb91ae9 |
@@ -27,23 +27,21 @@ if you look for more choices. The main differences are:
|
||||
- graphical installer whiptail
|
||||
- The script stops (fails) if it finds results of a previous installation. (The [debian-setup.sh](https://framagit.org/ojrandom/core/-/tree/dev/.debianinstall) will just jump over it.)
|
||||
- If something fails the script tries to clean up everything that was installed up to the point of failure. (That might cause trouble if certbot registered a certificate already.)
|
||||
- The script under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall) seems to be an older version of the scripts used for Streams
|
||||
+ [autoinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/autoinstall)
|
||||
+ [easyinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/easyinstall)
|
||||
- The script under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall) seems to be an older version of the scripts used for Streams, i.e. [autoinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/autoinstall) and [easyinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/easyinstall)
|
||||
|
||||
## Preconditions
|
||||
|
||||
Hardware
|
||||
|
||||
+ internet connection and router at home
|
||||
+ computer connected to your router (a Raspberry 3 will do for very small Hubs)
|
||||
+ computer connected to your router (a Raspberry 4 will do for very small Hubs)
|
||||
|
||||
Software
|
||||
|
||||
+ fresh installation of Debian 12 (bookworm)
|
||||
+ fresh installation of Debian 12 (bookworm) or Raspberry Pi OS
|
||||
+ router with open ports 80 and 443 for your web server
|
||||
|
||||
You can of course run the script on a VPS or any distant server as long as the above sotfware requirements are satisfied.
|
||||
You can of course run the script on a VPS or any distant server as long as the above software requirements are satisfied.
|
||||
|
||||
## How to run the script
|
||||
|
||||
@@ -82,6 +80,11 @@ Switch the verification off
|
||||
|
||||
util/config system verify_email 0
|
||||
|
||||
Check if updates from the repository do work
|
||||
|
||||
util/udall
|
||||
|
||||
|
||||
## What the script will do for you...
|
||||
|
||||
+ install everything required by your hubzilla instance, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||
@@ -101,7 +104,7 @@ The script is known to work without adjustments with
|
||||
|
||||
+ Hardware
|
||||
- standard PC with Debian 12 (bookworm)
|
||||
- Raspberry 4 with Raspbian, Debian 12 (TODO: needs confirmation after swich to Debian12)
|
||||
- Raspberry 5 with Raspberry Pi OS, Debian 12
|
||||
- for tesing purposes: under localhost inside a virtual machine, [KVM](https://wiki.debian.org/KVM)
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
@@ -151,8 +154,3 @@ It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
## Reminder for Different Web Wervers
|
||||
|
||||
For those of you who feel adventurous enough to use a different web server (i.e. Lighttpd...), don't forget that this script will install Apache or Nginx and that you can only have one web server listening to ports 80 & 443. Also, don't forget to tweak your daily shell script in /var/www/ accordingly.
|
||||
|
||||
@@ -93,9 +93,8 @@ freedns_key=
|
||||
# If left empty, both your database and user will be named after your zot instance (hubzilla, zap or misty)
|
||||
# Use custom name, at least fo the database, if you plan to run more than one hub/instance on the same server
|
||||
#
|
||||
zotserver_db_name=
|
||||
zotserver_db_user=
|
||||
zotserver_db_pass=$db_pass
|
||||
db_name=hubzilla
|
||||
db_user=hubzilla
|
||||
#
|
||||
#
|
||||
# Password for package mysql-server
|
||||
|
||||
@@ -150,7 +150,7 @@ function install_sendmail {
|
||||
function install_php {
|
||||
# openssl and mbstring are included in libapache2-mod-php
|
||||
print_info "installing php..."
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip"
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip php-intl php-bcmath"
|
||||
phpversion=$(php -v|grep --only-matching --perl-regexp "(PHP )\d+\.\\d+\.\\d+"|cut -c 5-7)
|
||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/$phpversion/apache2/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/$phpversion/apache2/php.ini
|
||||
@@ -160,8 +160,8 @@ function install_composer {
|
||||
print_info "We check if Composer is already downloaded"
|
||||
if [ ! -f /usr/local/bin/composer ]
|
||||
then
|
||||
EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
|
||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
EXPECTED_CHECKSUM="`wget -qO- https://composer.github.io/installer.sig`"
|
||||
wget https://getcomposer.org/installer -O composer-setup.php
|
||||
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
||||
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
|
||||
then
|
||||
@@ -171,6 +171,7 @@ function install_composer {
|
||||
fi
|
||||
php composer-setup.php --quiet
|
||||
RESULT=$?
|
||||
composer --version
|
||||
rm composer-setup.php
|
||||
# exit $RESULT
|
||||
# We install Composer globally
|
||||
@@ -181,7 +182,7 @@ function install_composer {
|
||||
fi
|
||||
cd $install_path
|
||||
export COMPOSER_ALLOW_SUPERUSER=1;
|
||||
/usr/local/bin/composer install --no-dev
|
||||
/usr/local/bin/composer install --no-dev --quiet
|
||||
/usr/local/bin/composer show
|
||||
export COMPOSER_ALLOW_SUPERUSER=0;
|
||||
}
|
||||
@@ -256,12 +257,18 @@ function create_zotserver_db {
|
||||
then
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $db_user@localhost IDENTIFIED BY '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $db_name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
else
|
||||
echo "database $db_name does exist already"
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $db_user@localhost IDENTIFIED BY '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $db_name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -301,10 +308,19 @@ function install_run_selfhost {
|
||||
# https://carol.selfhost.de/update?username=123456&password=supersafe
|
||||
#
|
||||
# the prefered way
|
||||
wget --output-document=$selfhostdir/$selfhostscript http://jonaspasche.de/selfhost-updater
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
if [ ! -f $selfhostdir/$selfhostscript ]
|
||||
then
|
||||
wget --output-document=$selfhostdir/$selfhostscript https://jonaspasche.de/selfhost-updater
|
||||
if [ ! -s $selfhostdir/$selfhostscript ]
|
||||
then
|
||||
die "Failed to download selfHOST file for dynDNS"
|
||||
fi
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
print_info "Wrote file to update dynamic IP. File: $selfhostdir/$selfhostscript"
|
||||
fi
|
||||
print_info "executing $selfhostdir/$selfhostscript update..."
|
||||
bash $selfhostdir/$selfhostscript update
|
||||
fi
|
||||
}
|
||||
@@ -380,7 +396,7 @@ function install_letsencrypt {
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||
fi
|
||||
nocheck_install "certbot python-certbot-apache"
|
||||
nocheck_install "certbot python3-certbot-apache"
|
||||
print_info "run certbot ..."
|
||||
certbot --apache -w $install_path -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
|
||||
service apache2 restart
|
||||
@@ -435,7 +451,7 @@ function configure_cron_daily {
|
||||
echo "echo \" \"" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - stopping apache and mysql...\"" >> /var/www/$cron_job
|
||||
echo "service apache2 stop" >> /var/www/$cron_job
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /var/www/$cron_job
|
||||
echo "systemctl stop mysql.service # to avoid inconsistencies" >> /var/www/$cron_job
|
||||
echo "#" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$cron_job
|
||||
echo "certbot renew --noninteractive" >> /var/www/$cron_job
|
||||
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -48,9 +48,10 @@ doc/html/
|
||||
.zotshrc
|
||||
# external repositories for themes/addons
|
||||
extend/
|
||||
# files generated by phpunit
|
||||
|
||||
# exclude test results and cache
|
||||
tests/.cache
|
||||
tests/.phpunit.result.cache
|
||||
tests/.phpunit*
|
||||
tests/results/
|
||||
|
||||
## exclude IDE files
|
||||
@@ -67,7 +68,6 @@ nbproject/
|
||||
# PHPStorm
|
||||
.idea/
|
||||
|
||||
|
||||
## composer
|
||||
# locally installed composer binary
|
||||
composer.phar
|
||||
@@ -87,6 +87,7 @@ vendor/bin/php-parse
|
||||
vendor/bin/phpcbf
|
||||
vendor/bin/phpcs
|
||||
vendor/bin/phpmd
|
||||
vendor/bin/phpstan*
|
||||
vendor/bin/phpunit
|
||||
vendor/composer/pcre/
|
||||
vendor/composer/xdebug-handler/
|
||||
@@ -98,18 +99,11 @@ vendor/pdepend/
|
||||
vendor/phar-io/
|
||||
vendor/php-mock/
|
||||
vendor/phpmd/
|
||||
vendor/phpstan
|
||||
vendor/phpunit/
|
||||
vendor/psr/container/
|
||||
vendor/sebastian/
|
||||
vendor/squizlabs/
|
||||
vendor/symfony/config/
|
||||
vendor/symfony/dependency-injection/
|
||||
vendor/symfony/deprecation-contracts/
|
||||
vendor/symfony/filesystem/
|
||||
vendor/symfony/polyfill-ctype/
|
||||
vendor/symfony/polyfill-mbstring/
|
||||
vendor/symfony/polyfill-php80/
|
||||
vendor/symfony/service-contracts/
|
||||
vendor/theseer/
|
||||
# /info is a directory containing site-specific HTML documents
|
||||
/info/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
stages:
|
||||
- pretest
|
||||
- test
|
||||
- deploy
|
||||
|
||||
@@ -25,22 +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-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
|
||||
@@ -52,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+\%/'
|
||||
|
||||
@@ -83,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+\%/'
|
||||
|
||||
@@ -99,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
|
||||
|
||||
|
||||
318
CHANGELOG
318
CHANGELOG
@@ -1,6 +1,324 @@
|
||||
Hubzilla 10.6.1 (2025-11-21)
|
||||
- Fix insufficient target attribution for forums
|
||||
- Fix reshare regression in forum logic
|
||||
|
||||
|
||||
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
|
||||
- Remove possible leading @ before processing webfinger address
|
||||
- Updated debian install script
|
||||
- Calculate observer.baseurl from xchan_url instead of xchan_connurl
|
||||
- Refactor unparse_url() to allow return of a custom field set only and add tests
|
||||
- Slightly improve event object rendering
|
||||
- Update smarty library to version 5 for PHP 8.4 compatibility
|
||||
- Remove vendor/symfony from gitignore file
|
||||
- Update composer libraries
|
||||
- Add contextHistory field to activities and prefer it over context when consuming
|
||||
- Implement highlight button in jot editor
|
||||
- Add test results and PHPStan to gitignore
|
||||
- Update spanish strings
|
||||
- Remove EpubMeta library in favor of a custom solution
|
||||
- Configue gd for jpeg support in CI
|
||||
- Add error message on missing owa auth headers
|
||||
- Add Zotlabs\Tests namespace to autloader in dev
|
||||
- Add dba_pdo::update method
|
||||
- Add dba_pdo::insert method
|
||||
- Rewrite redbasic javascript to remove jquery dependency
|
||||
- Add security policy SECURITY.md
|
||||
|
||||
Bugfixes
|
||||
- Fix notifications for likes on our comments
|
||||
- Fix fullscreen view
|
||||
- Fix boxy scheme text alignment for comments
|
||||
- Fix poll date string to match with the autotime string
|
||||
- Fix owner hash not set correctly when editing a post/comment
|
||||
- Fix an issue where some participants could not post to forums
|
||||
- Fix navbar selector conflict with possible additional navbars when using a cover photo
|
||||
- Fix target and tgt_type not set for sourced rss items if we rewrite them to our own
|
||||
- Fix auto save draft not set correctly
|
||||
- Fix cover height calculation
|
||||
|
||||
Addons
|
||||
- Diaspora: revisit import_diaspora_account()
|
||||
- Pubcrawl: escape quotation marks in ActivityStreams link header
|
||||
- Wiki: fixed wiki_page_list.tpl to use bootstrap class for layout
|
||||
- BBmath: fix orientation for inline math
|
||||
- BBmath: document imagemagick permissions
|
||||
- Pubcrawl: ensure we select the correct hubloc hash when extending recipients list
|
||||
- Msg_footer: do not add footer on edit, also dismiss anything but a create activity
|
||||
- Pubcrawl: refactor activitypub addressing
|
||||
- Wiki: added space to preview panel
|
||||
- Startpage: update help text and some cleanup
|
||||
|
||||
|
||||
Hubzilla 10.0.8 (2025-02-01)
|
||||
- Fix duplicating terms/iconfig in addToCollectionAndSync()
|
||||
- Refactor Daemon/Importdoc for better SQL performance when looking up outdated entries
|
||||
- Tweak SQL in mod sse_bs for possible performance improvements
|
||||
- Fix PHP warnings
|
||||
- Do not run post_local hook on add activities in pubcrawl addon
|
||||
- Do not run post_local hook on add activities in diaspora addon
|
||||
- Remove old rawmsg/fields before storing new rawmsg in pubcrawl addon
|
||||
- Fix retractions in diaspora addon
|
||||
|
||||
|
||||
Hubzilla 10.0.7 (2025-01-22)
|
||||
- Fix ownership check in consume_feed()
|
||||
- Fix toast() if notification contains non-ascii characters
|
||||
- Fix regression in notifications filter
|
||||
|
||||
|
||||
Hubzilla 10.0.6 (2025-01-05)
|
||||
- Fix entries where primary location data is not complete not dismissed early
|
||||
- Fix query to cleanup outdated doc entries called multiple times
|
||||
- Fix query to cleanup outdated doc entries
|
||||
|
||||
|
||||
Hubzilla 10.0.5 (2024-12-29)
|
||||
- Fix another instance of drop_item() not having permission to drop items
|
||||
|
||||
|
||||
Hubzilla 10.0.4 (2024-12-26)
|
||||
- Fix missing argument name
|
||||
|
||||
|
||||
Hubzilla 10.0.3 (2024-12-26)
|
||||
- Fix regression in Daemon/Channel_purge which could cause a possible infinite loop
|
||||
- Fix regression in Daemon/Expire which could cause a infinite loop
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
"air" is a branch name for revision of Account-Invite-Register at the Hubzilla project
|
||||
|
||||
Invite:
|
||||
* Rewritten and now language template driven
|
||||
* Selectable templates for the invite mails
|
||||
* Invitor may add personal notes in the mailtext
|
||||
+ Invite codes are bound to the recipients email address
|
||||
* Invite mod never more creates accounts
|
||||
* new db scheme for table register
|
||||
* existing register table will be migrated to the new schema even when detected at runtime
|
||||
* Bugfix: creating invite codes when admin only calls Invite w/o any further action
|
||||
* account library revision also together with invite mod
|
||||
* Depending on config: Users may send invitations also
|
||||
* Invitations expires, controlled by the invitor
|
||||
* Changed and new configs:
|
||||
* * invitation_only As usual before
|
||||
* * invitation_also Beside other registration policies, invitations may be used also
|
||||
* * invitation_max_per_day defaults 50, may be changed in adminUI admin>site
|
||||
* * invitation_max_per_user defaults 4
|
||||
* Requirements:
|
||||
* * Addon language has to be installed
|
||||
|
||||
Register:
|
||||
* Register panel (form) and js interaction changed
|
||||
* Unused registrations expire
|
||||
* Depending on config, anonymous registrations (w/o email) are supported
|
||||
* :... dont't panic, that may let grow security
|
||||
* Even anonymous users have to confirm their registration
|
||||
* Registrations may be enabled / disabled time driven for each day in the week (dudy)
|
||||
* Unsoliced registration floods may be blocked
|
||||
* Limited registrations from one single source ip
|
||||
* Using one additional log file, to easy interfare with f2b
|
||||
|
||||
Account:
|
||||
* An user account always becomes created only if all depending conditions are satisfied
|
||||
* AdminUI for site configuration, accounts and registrations enhancements
|
||||
* Still untouched, but accountUI needs enhanced async control in case for mass delete
|
||||
with deep level of recursion cascade of the dependencies (channels etc). An open TODO
|
||||
since years for instances with many much users and channels.
|
||||
|
||||
History:
|
||||
2020.03 Hubzilla Prod version 4.6 (master branch) of hubzilla/core was the base for AIR
|
||||
that was assigned Version 4.6.2 at sn/core
|
||||
2021.02 Hubzilla Prod version 5.2.1 (master branch) of hubzilla/core was new base for AIR
|
||||
that was assigned version 5.2.2 at sn/core (air.5)
|
||||
plus adjustment of hubzilla 5.2.2 (master) to sn/core (air.5) version 5.2.9
|
||||
|
||||
|
||||
31
SECURITY.md
Normal file
31
SECURITY.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Hubzilla Security Policy
|
||||
|
||||
The [Hubzilla] Project takes security, privacy and user control over personal data seriously. We ask that any security issues be disclosed to us in a responsible manner to allow us time to remediate the issues, and site administrators time to upgrade before information about the issue is made public.
|
||||
|
||||
This document outlines security procedures and policies for the Hubzilla project. It covers the following components:
|
||||
|
||||
* The Hubzilla core repository: https://framagit.org/hubzilla/core
|
||||
* The official addon repository: https://framagit.org/hubzilla/addons
|
||||
* The official themes repository: https://framagit.org/hubzilla/themes
|
||||
* The official widgets repository: https://framagit.org/hubzilla/widgets
|
||||
|
||||
## Coordinated Disclosure Guidelines
|
||||
|
||||
We are committed to working with security researchers to verify, reproduce, and respond to legitimate reported vulnerabilities. You can help us by following these simple guidelines:
|
||||
|
||||
* Submit suspected vulnerabilities by email to `security@hubzilla.org`, or as a confidential issue in the relevant repository listed above.
|
||||
* Provide clear instructions on how to reproduce the issue, and if possible, a minimal Proof of Concept (PoC) exploit.
|
||||
* We will acknowledge your submission as soon as we can, and will keep you updated as it is being processed. We may ask for more information, or clarifications about the issue or the steps to reproduce it during this time.
|
||||
* We will assign a CVE to the issue once it is confirmed.
|
||||
* We will do our best to fix the issue as soon as we can after it has been confirmed. We request that information about the vulnerability or details about how to exploit it is not disclosed to other parties until after the fix is released and some time has passed, to allow site administrators to upgrade. We will normally make the CVE public one month after a fix has been released. (This grace period can differ based on severity, and can be negotiated.)
|
||||
* Please perform all tests against a local instance of the software, and refrain from running any Denial of Service or automated testing tools against public hubs or the project managers (and their partners') infrastructure.
|
||||
* If the issue belongs to a third party module that we depend on, we may help with reporting it upstream if the submitter wants us to.
|
||||
|
||||
## Comments on this Policy
|
||||
|
||||
We welcome comments and suggestions for improving this policy. You can reach us at:
|
||||
|
||||
* Our ticketing system: https://framagit.org/hubzilla/core/-/issues
|
||||
* By sending us an email at `security@hubzilla.org`.
|
||||
|
||||
[Hubzilla]: https://hubzilla.org
|
||||
@@ -6,23 +6,28 @@ class Cache_embeds {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
if(! $argc == 2)
|
||||
if(!$argc == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
$c = q("select body from item where id = %d ",
|
||||
dbesc(intval($argv[1]))
|
||||
$c = q("select uid, aid, body, item_private from item where uuid = '%s'",
|
||||
dbesc($argv[1])
|
||||
);
|
||||
|
||||
if(! $c)
|
||||
if(!$c) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item = $c[0];
|
||||
|
||||
// bbcode conversion by default processes embeds that aren't already cached.
|
||||
// Ignore the returned html output.
|
||||
|
||||
bbcode($item['body']);
|
||||
|
||||
// photocache addon hook to prefetch one copy of public item images for the sys channel
|
||||
call_hooks('cache_prefetch_hook', $item);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,21 @@ class Importdoc {
|
||||
|
||||
self::update_docs_dir('doc/*');
|
||||
|
||||
$sys = get_sys_channel();
|
||||
|
||||
// remove old files that weren't updated (indicates they were most likely deleted).
|
||||
$i = q("select id from item where uid = %d and item_type = 5 and edited < %s - INTERVAL %s",
|
||||
intval($sys['channel_id']),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('14 DAY')
|
||||
);
|
||||
|
||||
if ($i) {
|
||||
foreach ($i as $iv) {
|
||||
drop_item($iv['id'], uid: $sys['channel_id']);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@@ -41,18 +56,6 @@ class Importdoc {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove old files that weren't updated (indicates they were most likely deleted).
|
||||
$i = q("select * from item where item_type = 5 and edited < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval('14 DAY', true)
|
||||
);
|
||||
|
||||
if ($i) {
|
||||
foreach ($i as $iv) {
|
||||
drop_item($iv['id'], DROPITEM_NORMAL, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -323,7 +323,13 @@ class Notifier {
|
||||
self::$encoded_item = json_decode($m, true);
|
||||
}
|
||||
else {
|
||||
self::$encoded_item = Activity::build_packet(Activity::encode_activity($target_item), self::$channel, false);
|
||||
$activity = Activity::encode_activity($target_item);
|
||||
|
||||
if (!$activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$encoded_item = Activity::build_packet($activity, self::$channel, false);
|
||||
}
|
||||
|
||||
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
|
||||
@@ -340,6 +346,10 @@ class Notifier {
|
||||
|
||||
$relay_to_owner = (!$top_level_post && intval($target_item['item_origin']) && comment_local_origin($target_item));
|
||||
|
||||
if (self::$channel['channel_hash'] === $target_item['owner_xchan']) {
|
||||
$relay_to_owner = false;
|
||||
}
|
||||
|
||||
// $cmd === 'relay' indicates the owner is sending it to the original recipients
|
||||
// don't allow the item in the relay command to relay to owner under any circumstances, it will loop
|
||||
|
||||
|
||||
@@ -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'] .= ' ';
|
||||
@@ -616,19 +615,11 @@ class Activity {
|
||||
if (!empty($cnv)) {
|
||||
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
|
||||
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
|
||||
$ret['contextHistory'] = $cnv;
|
||||
}
|
||||
$ret['context'] = $cnv;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -646,6 +637,55 @@ class Activity {
|
||||
$ret['tag'] = $t;
|
||||
}
|
||||
|
||||
// TODO: Do not replace the if the owner is a forum.
|
||||
// Receivers will not be able to fetch the original in that case.
|
||||
if (str_contains($i['body'], '[/share]') && !$i['owner']['xchan_pubforum']) {
|
||||
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;
|
||||
@@ -694,7 +734,7 @@ class Activity {
|
||||
if (is_array($t) && !array_key_exists('type', $t))
|
||||
$t['type'] = 'Hashtag';
|
||||
|
||||
if (is_array($t) && (array_key_exists('href', $t) || array_key_exists('id', $t)) && array_key_exists('name', $t)) {
|
||||
if (is_array($t) && (array_key_exists('href', $t) || array_key_exists('id', $t) || isset($t['icon']['url'])) && array_key_exists('name', $t)) {
|
||||
switch ($t['type']) {
|
||||
case 'Hashtag':
|
||||
$ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])];
|
||||
@@ -709,7 +749,7 @@ class Activity {
|
||||
break;
|
||||
|
||||
case 'Emoji':
|
||||
$ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['id'], 'term' => escape_tags($t['name']), 'imgurl' => $t['icon']['url']];
|
||||
$ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['id'] ?? $t['icon']['url'], 'term' => escape_tags($t['name']), 'imgurl' => $t['icon']['url']];
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -802,7 +842,7 @@ class Activity {
|
||||
|
||||
$ret = [];
|
||||
|
||||
if (isset($item['attachment'])) {
|
||||
if (isset($item['attachment']) && is_array($item['attachment'])) {
|
||||
$ptr = $item['attachment'];
|
||||
if (!array_key_exists(0, $ptr)) {
|
||||
$ptr = [$ptr];
|
||||
@@ -852,6 +892,8 @@ class Activity {
|
||||
$entry['type'] = $att['mediaType'];
|
||||
} elseif (array_key_exists('type', $att) && $att['type'] === 'Image') {
|
||||
$entry['type'] = 'image/jpeg';
|
||||
} elseif (array_key_exists('type', $att) && $att['type'] === 'Link') {
|
||||
$entry['type'] = 'text/uri-list';
|
||||
}
|
||||
if (array_key_exists('name', $att) && $att['name']) {
|
||||
$entry['name'] = html2plain(purify_html($att['name']), 256);
|
||||
@@ -941,36 +983,8 @@ class Activity {
|
||||
|
||||
}
|
||||
|
||||
if ($ret['type'] === 'emojiReaction') {
|
||||
// There may not be an object for these items for legacy reasons - it should be the conversation parent.
|
||||
$p = q("select * from item where mid = '%s' and uid = %d",
|
||||
dbesc($i['parent_mid']),
|
||||
intval($i['uid'])
|
||||
);
|
||||
if ($p) {
|
||||
xchan_query($p, true);
|
||||
$p = fetch_post_tags($p);
|
||||
$i['obj'] = self::encode_item($p[0]);
|
||||
|
||||
// convert to zot6 emoji reaction encoding which uses the target object to indicate the
|
||||
// specific emoji instead of overloading the verb or type.
|
||||
|
||||
$im = explode('#', $i['verb']);
|
||||
if ($im && count($im) > 1)
|
||||
$emoji = $im[1];
|
||||
if (preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
|
||||
$ln = $match[2];
|
||||
}
|
||||
|
||||
$i['tgt_type'] = 'Image';
|
||||
|
||||
$i['target'] = [
|
||||
'type' => 'Image',
|
||||
'name' => $emoji,
|
||||
'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
|
||||
];
|
||||
|
||||
}
|
||||
if ($ret['type'] === 'EmojiReact') {
|
||||
$ret['content'] = $i['body'];
|
||||
}
|
||||
|
||||
if (strpos($i['mid'], z_root() . '/item/') !== false) {
|
||||
@@ -985,15 +999,15 @@ class Activity {
|
||||
|
||||
$ret['diaspora:guid'] = $i['uuid'];
|
||||
|
||||
if (isset($i['title']) && $i['title'])
|
||||
$ret['name'] = html2plain(bbcode($i['title'], ['cache' => true]));
|
||||
if (!empty($i['title']))
|
||||
$ret['name'] = html2plain(bbcode($i['title']));
|
||||
|
||||
if (isset($i['summary']) && $i['summary'])
|
||||
$ret['summary'] = bbcode($i['summary'], ['cache' => true]);
|
||||
if (!empty($i['summary']))
|
||||
$ret['summary'] = bbcode($i['summary']);
|
||||
|
||||
if ($ret['type'] === 'Announce') {
|
||||
$tmp = preg_replace('/\[share(.*?)\[\/share\]/ism', EMPTY_STR, $i['body']);
|
||||
$ret['content'] = bbcode($tmp, ['cache' => true]);
|
||||
$ret['content'] = bbcode($tmp);
|
||||
$ret['source'] = [
|
||||
'content' => $i['body'],
|
||||
'mediaType' => 'text/bbcode'
|
||||
@@ -1009,7 +1023,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($i['app']) && $i['app']) {
|
||||
if (!empty($i['app'])) {
|
||||
$ret['generator'] = ['type' => 'Application', 'name' => $i['app']];
|
||||
}
|
||||
if (!empty($i['location']) || !empty($i['coord'])) {
|
||||
@@ -1050,6 +1064,7 @@ class Activity {
|
||||
if (!empty($cnv)) {
|
||||
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
|
||||
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
|
||||
$ret['contextHistory'] = $cnv;
|
||||
}
|
||||
$ret['context'] = $cnv;
|
||||
}
|
||||
@@ -1060,7 +1075,7 @@ class Activity {
|
||||
else
|
||||
return [];
|
||||
|
||||
if (isset($i['obj']) && $i['obj']) {
|
||||
if (!empty($i['obj'])) {
|
||||
if (!is_array($i['obj'])) {
|
||||
$i['obj'] = json_decode($i['obj'], true);
|
||||
}
|
||||
@@ -1088,7 +1103,7 @@ class Activity {
|
||||
$ret['type'] = 'Invite';
|
||||
}
|
||||
|
||||
if (isset($i['target']) && $i['target']) {
|
||||
if (!empty($i['target'])) {
|
||||
if (!is_array($i['target'])) {
|
||||
$i['target'] = json_decode($i['target'], true);
|
||||
}
|
||||
@@ -1099,12 +1114,10 @@ class Activity {
|
||||
return [];
|
||||
}
|
||||
|
||||
/* this should not be needed
|
||||
$t = self::encode_taxonomy($i);
|
||||
if ($t) {
|
||||
$ret['tag'] = $t;
|
||||
}
|
||||
*/
|
||||
|
||||
$a = self::encode_attachment($i, true);
|
||||
if ($a) {
|
||||
@@ -1115,7 +1128,6 @@ class Activity {
|
||||
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
|
||||
}
|
||||
|
||||
|
||||
$hookinfo = [
|
||||
'item' => $i,
|
||||
'encoded' => $ret
|
||||
@@ -1716,9 +1728,9 @@ class Activity {
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $person_obj['name'] ?? '';
|
||||
$name = ((isset($person_obj['name'])) ? escape_tags($person_obj['name']) : '');
|
||||
if (!$name) {
|
||||
$name = $person_obj['preferredUsername'] ?? '';
|
||||
$name = ((isset($person_obj['preferredUsername'])) ? escape_tags($person_obj['preferredUsername']) : '');
|
||||
}
|
||||
if (!$name) {
|
||||
$name = t('Unknown');
|
||||
@@ -1727,13 +1739,11 @@ class Activity {
|
||||
$webfinger_addr = ((isset($person_obj['webfinger'])) ? str_replace('acct:', '', $person_obj['webfinger']) : '');
|
||||
$hostname = '';
|
||||
$baseurl = '';
|
||||
$site_url = '';
|
||||
|
||||
$m = parse_url($url);
|
||||
if ($m) {
|
||||
$hostname = $m['host'];
|
||||
$baseurl = $m['scheme'] . '://' . $m['host'] . ((isset($m['port'])) ? ':' . $m['port'] : '');
|
||||
$site_url = $m['scheme'] . '://' . $m['host'];
|
||||
$hostname = unparse_url($m, ['host']);
|
||||
$baseurl = unparse_url($m, ['scheme', 'host', 'port']);
|
||||
}
|
||||
|
||||
if (!$webfinger_addr && !empty($person_obj['preferredUsername']) && $hostname) {
|
||||
@@ -1835,7 +1845,7 @@ class Activity {
|
||||
|
||||
q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($site_url)
|
||||
dbesc($baseurl)
|
||||
);
|
||||
|
||||
// update existing xchan record
|
||||
@@ -2148,34 +2158,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 +2215,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 +2227,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 +2265,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 +2316,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 +2403,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 +2485,8 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
$tag = (($poster) ? '[video poster="' . $poster . '"]' : '[video]' );
|
||||
$tag = (($poster) ? '[video poster=\'' . $poster . '\']' : '[video]' );
|
||||
|
||||
$ptr = null;
|
||||
|
||||
if ($act->objprop('url')) {
|
||||
@@ -2619,7 +2635,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 +2647,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 +2659,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if (!(isset($s['plink']) && $s['plink'])) {
|
||||
if (empty($s['plink'])) {
|
||||
$s['plink'] = $s['mid'];
|
||||
}
|
||||
|
||||
@@ -2719,8 +2735,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 +2784,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 +2799,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 +2962,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');
|
||||
|
||||
@@ -2974,7 +2993,10 @@ class Activity {
|
||||
// This isn't perfect but the best we can do for now.
|
||||
$item['comment_policy'] = ((isset($act->data['commentPolicy'])) ? $act->data['commentPolicy'] : 'authenticated');
|
||||
|
||||
if (!empty($act->obj['context'])) {
|
||||
if (!empty($act->obj['contextHistory'])) {
|
||||
IConfig::Set($item, 'activitypub', 'context', $act->obj['contextHistory'], 1);
|
||||
}
|
||||
elseif (!empty($act->obj['context'])) {
|
||||
IConfig::Set($item, 'activitypub', 'context', $act->obj['context'], 1);
|
||||
}
|
||||
|
||||
@@ -3009,7 +3031,7 @@ class Activity {
|
||||
|
||||
if (intval($parent[0]['item_private']) === 0) {
|
||||
if (intval($item['item_private'])) {
|
||||
$item['item_restrict'] = $item['item_restrict'] | 1;
|
||||
$item['item_restrict'] = ((isset($item['item_restrict'])) ? $item['item_restrict'] | 1 : 1);
|
||||
$item['allow_cid'] = '<' . $channel['channel_hash'] . '>';
|
||||
$item['allow_gid'] = $item['deny_cid'] = $item['deny_gid'] = '';
|
||||
}
|
||||
@@ -3026,7 +3048,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (isset($item['term']) && !PConfig::Get($channel['channel_id'], 'system', 'no_smilies')) {
|
||||
foreach ($item['term'] as $t) {
|
||||
if ($t['ttype'] === TERM_EMOJI) {
|
||||
@@ -3040,6 +3062,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: not implemented
|
||||
// self::rewrite_mentions($item);
|
||||
@@ -3063,8 +3086,7 @@ class Activity {
|
||||
}
|
||||
|
||||
if ($x['success']) {
|
||||
|
||||
if ($relay && $channel['channel_hash'] === $x['item']['owner_xchan'] && $x['item']['verb'] !== 'Add' && !$isCollectionOperation) {
|
||||
if ($relay && $channel['channel_hash'] === $x['item']['owner_xchan'] && $x['item']['verb'] !== 'Add' && !$is_collection_operation) {
|
||||
$approval = Activity::addToCollection($channel, $act->data, $x['item']['parent_mid'], $x['item'], deliver: false);
|
||||
}
|
||||
|
||||
@@ -3082,38 +3104,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3162,7 +3163,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']);
|
||||
@@ -3170,7 +3171,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);
|
||||
@@ -3405,10 +3406,10 @@ class Activity {
|
||||
if (array_key_exists('startTime', $act) && strpos($act['startTime'], -1, 1) === 'Z') {
|
||||
$adjust = true;
|
||||
$event['adjust'] = 1;
|
||||
$event['dtstart'] = datetime_convert('UTC', 'UTC', $event['startTime'] . (($adjust) ? '' : 'Z'));
|
||||
$event['dtstart'] = datetime_convert('UTC', 'UTC', $act['startTime'] . (($adjust) ? '' : 'Z'));
|
||||
}
|
||||
if (array_key_exists('endTime', $act)) {
|
||||
$event['dtend'] = datetime_convert('UTC', 'UTC', $event['endTime'] . (($adjust) ? '' : 'Z'));
|
||||
$event['dtend'] = datetime_convert('UTC', 'UTC', $act['endTime'] . (($adjust) ? '' : 'Z'));
|
||||
}
|
||||
else {
|
||||
$event['nofinish'] = true;
|
||||
@@ -3607,38 +3608,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'] ?? [];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3694,6 +3725,8 @@ class Activity {
|
||||
|
||||
return [
|
||||
'zot' => z_root() . '/apschema#',
|
||||
|
||||
'contextHistory' => 'https://w3id.org/fep/171b/contextHistory',
|
||||
'schema' => 'http://schema.org#',
|
||||
'ostatus' => 'http://ostatus.org#',
|
||||
'diaspora' => 'https://diasporafoundation.org/ns/',
|
||||
@@ -3716,8 +3749,9 @@ class Activity {
|
||||
'guid' => 'diaspora:guid',
|
||||
|
||||
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
|
||||
'Hashtag' => 'as:Hashtag'
|
||||
'Hashtag' => 'as:Hashtag',
|
||||
|
||||
'quoteUrl' => 'as:quoteUrl',
|
||||
];
|
||||
|
||||
}
|
||||
@@ -3757,10 +3791,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) {
|
||||
@@ -3773,16 +3806,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) {
|
||||
@@ -3794,6 +3826,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) {
|
||||
@@ -3868,4 +3917,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'),
|
||||
|
||||
@@ -24,10 +24,16 @@ class Connect {
|
||||
|
||||
$uid = $channel['channel_id'];
|
||||
|
||||
if (strpos($url,'@') === false && strpos($url,'/') === false) {
|
||||
// If we get just a channel name and it is not an URL turn it into a local webbie
|
||||
if (!str_contains($url, '@') && strpos($url,'/') === false) {
|
||||
$url = $url . '@' . App::get_hostname();
|
||||
}
|
||||
|
||||
// Remove a possible leading @
|
||||
if (str_starts_with($url, '@')) {
|
||||
$url = ltrim($url, '@');
|
||||
}
|
||||
|
||||
$result = [ 'success' => false, 'message' => '' ];
|
||||
|
||||
$my_perms = false;
|
||||
|
||||
@@ -35,7 +35,7 @@ class DReport {
|
||||
}
|
||||
|
||||
function addto_update($status) {
|
||||
$this->status = $this->status . ' ' . $status;
|
||||
$this->status = $this->status . ', ' . $status;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,8 +89,14 @@ class DReport {
|
||||
if(array_key_exists('reject',$dr) && intval($dr['reject']))
|
||||
return false;
|
||||
|
||||
if(! ($dr['sender']))
|
||||
if (!$dr['sender']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// do not store dismissed create activities
|
||||
if ($dr['status'] === 'not a collection activity') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is the sender one of our channels?
|
||||
|
||||
|
||||
@@ -95,8 +95,8 @@ class Enotify {
|
||||
if (array_key_exists('verb', $params['item'])) {
|
||||
// localize_item() alters the original item so make a copy first
|
||||
$i = $params['item'];
|
||||
logger('calling localize');
|
||||
localize_item($i);
|
||||
// logger('calling localize');
|
||||
// localize_item($i);
|
||||
$title = $i['title'];
|
||||
$body = $i['body'];
|
||||
$private = (($i['item_private']) || intval($i['item_obscured']));
|
||||
@@ -131,9 +131,9 @@ class Enotify {
|
||||
logger('notification: mail');
|
||||
$subject = sprintf( t('[$Projectname:Notify] New direct message received at %s'), $sitename);
|
||||
|
||||
$preamble = sprintf( t('%1$s sent you a new direct message at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$preamble = sprintf( t('%1$s sent you a new private message at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s sent you %2$s.'), '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', '[zrl=$itemlink]' . t('a direct message') . '[/zrl]');
|
||||
$sitelink = t('Please visit %s to view and/or reply to your direct messages.');
|
||||
$sitelink = t('Please visit %s to view and/or reply to your private messages.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl . '/hq/' . gen_link_id($params['item']['mid']));
|
||||
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/hq/' . gen_link_id($params['item']['mid']) . '">' . $sitename . '</a>');
|
||||
$itemlink = $siteurl . '/hq/' . gen_link_id($params['item']['mid']);
|
||||
@@ -146,7 +146,7 @@ class Enotify {
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
$action = (($moderated) ? t('requested to comment on') : t('commented on'));
|
||||
$action = (($moderated) ? t('requested to post in') : t('posted in'));
|
||||
|
||||
if(array_key_exists('item',$params)) {
|
||||
|
||||
@@ -164,8 +164,8 @@ class Enotify {
|
||||
if(activity_match($params['verb'], ['Dislike', ACTIVITY_DISLIKE]))
|
||||
$action = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_SHARE))
|
||||
$action = t('repeated');
|
||||
if(activity_match($params['verb'], [ACTIVITY_SHARE]))
|
||||
$action = (($moderated) ? t('requested to repeat') : t('repeated'));
|
||||
|
||||
}
|
||||
|
||||
@@ -213,28 +213,36 @@ class Enotify {
|
||||
//$possess_desc = str_replace('<!item_type!>',$possess_desc);
|
||||
|
||||
// "a post"
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
|
||||
// "George Bull's post"
|
||||
if($p)
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
|
||||
if($p) {
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$p[0]['author']['xchan_name'],
|
||||
$item_post_type);
|
||||
$parent_item['author']['xchan_name'],
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
if ($parent_item['owner']['xchan_hash'] === $recip['channel_hash'] && intval($parent_item['item_wall'])) {
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
|
||||
// Some mail softwares relies on subject field for threading.
|
||||
// So, we cannot have different subjects for notifications of the same thread.
|
||||
@@ -263,7 +271,7 @@ class Enotify {
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]))) {
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE, 'Announce']))) {
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
pop_lang();
|
||||
@@ -308,7 +316,6 @@ class Enotify {
|
||||
$item_post_type = item_post_type($p[0]);
|
||||
// $private = $p[0]['item_private'];
|
||||
$parent_id = $p[0]['id'];
|
||||
|
||||
$parent_item = $p[0];
|
||||
|
||||
//$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked'));
|
||||
@@ -320,14 +327,18 @@ class Enotify {
|
||||
if(activity_match($params['item']['verb'], ['Dislike', ACTIVITY_DISLIKE]))
|
||||
$verb = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
if(activity_match($params['item']['verb'], [ACTIVITY_SHARE]))
|
||||
$verb = (($moderated) ? t('requested to repeat') : t('repeated'));
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] === $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
if ($parent_item['author']['xchan_hash'] === $recip['channel_hash']) {
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$verb,
|
||||
$itemlink,
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
else {
|
||||
pop_lang();
|
||||
return;
|
||||
@@ -500,9 +511,14 @@ class Enotify {
|
||||
*/
|
||||
|
||||
|
||||
$hash = ((in_array($params['verb'], ['Create', 'Update'])) ? $params['item']['uuid'] : $params['item']['thr_parent_uuid']);
|
||||
|
||||
if (!$hash) {
|
||||
$hash = new_uuid();
|
||||
}
|
||||
|
||||
$datarray = [];
|
||||
$datarray['hash'] = $params['item']['uuid'] ?? new_uuid();
|
||||
$datarray['hash'] = $hash;
|
||||
$datarray['sender_hash'] = $sender['xchan_hash'];
|
||||
$datarray['xname'] = $sender['xchan_name'];
|
||||
$datarray['url'] = $sender['xchan_url'];
|
||||
@@ -561,8 +577,9 @@ class Enotify {
|
||||
dbesc($datarray['otype'])
|
||||
);
|
||||
|
||||
$r = q("select id from notify where hash = '%s' and ntype = %d and uid = %d limit 1",
|
||||
$r = q("select id from notify where hash = '%s' and link = '%s' and ntype = %d and uid = %d limit 1",
|
||||
dbesc($datarray['hash']),
|
||||
dbesc($itemlink),
|
||||
intval($datarray['ntype']),
|
||||
intval($recip['channel_id'])
|
||||
);
|
||||
@@ -840,8 +857,8 @@ class Enotify {
|
||||
}
|
||||
else {
|
||||
$itemem_text = (($item['item_thread_top'])
|
||||
? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
? (($item['obj_type'] === 'Question') ? t('started a poll') : t('started a conversation'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('posted in %s\'s conversation'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
);
|
||||
|
||||
if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
|
||||
@@ -853,12 +870,7 @@ class Enotify {
|
||||
|
||||
if($item['edited'] > $item['created']) {
|
||||
$edit = true;
|
||||
if($item['item_thread_top']) {
|
||||
$itemem_text = sprintf( t('edited a post dated %s'), relative_date($item['created']));
|
||||
}
|
||||
else {
|
||||
$itemem_text = sprintf( t('edited a comment dated %s'), relative_date($item['created']));
|
||||
}
|
||||
$itemem_text = sprintf( t('edited a message dated %s'), relative_date($item['created']));
|
||||
}
|
||||
|
||||
|
||||
@@ -878,7 +890,7 @@ class Enotify {
|
||||
'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
|
||||
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
|
||||
// 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''),
|
||||
'b64mid' => (($item['uuid']) ? $item['uuid'] : ''),
|
||||
'b64mid' => ((in_array($item['verb'] , ['Like', 'Dislike', 'Announce']) && !empty($item['thr_parent_uuid'])) ? $item['thr_parent_uuid'] : $item['uuid'] ?? ''),
|
||||
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])),
|
||||
'thread_top' => (($item['item_thread_top']) ? true : false),
|
||||
'message' => bbcode(escape_tags($itemem_text)),
|
||||
@@ -898,14 +910,13 @@ class Enotify {
|
||||
}
|
||||
|
||||
static public function format_notify($tt) {
|
||||
|
||||
$message = trim(strip_tags(bbcode($tt['msg'])));
|
||||
|
||||
if(strpos($message, $tt['xname']) === 0)
|
||||
$message = substr($message, strlen($tt['xname']) + 1);
|
||||
|
||||
$x = [
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['link'] : z_root() . '/notify/view/' . $tt['id']),
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_INTRO) ? z_root() . '/notify/view/' . $tt['id'] : $tt['link']),
|
||||
'name' => $tt['xname'],
|
||||
'url' => $tt['url'],
|
||||
'photo' => $tt['photo'],
|
||||
@@ -917,11 +928,9 @@ class Enotify {
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_intros($rr) {
|
||||
|
||||
return [
|
||||
'notify_link' => z_root() . '/connections#' . $rr['abook_id'],
|
||||
'name' => $rr['xchan_name'],
|
||||
|
||||
@@ -13,6 +13,7 @@ class IConfig {
|
||||
static public function Get(&$item, $family, $key, $default = false) {
|
||||
|
||||
$is_item = false;
|
||||
$iid = null;
|
||||
|
||||
if(is_array($item)) {
|
||||
$is_item = true;
|
||||
@@ -27,12 +28,13 @@ class IConfig {
|
||||
elseif(intval($item))
|
||||
$iid = $item;
|
||||
|
||||
if(! $iid)
|
||||
if (!$iid)
|
||||
return $default;
|
||||
|
||||
|
||||
if(is_array($item) && array_key_exists('iconfig',$item) && is_array($item['iconfig'])) {
|
||||
foreach($item['iconfig'] as $c) {
|
||||
if($c['iid'] == $iid && $c['cat'] == $family && $c['k'] == $key)
|
||||
if (isset($c['iid']) && $c['iid'] == $iid && isset($c['cat']) && $c['cat'] == $family && isset($c['k']) && $c['k'] == $key)
|
||||
return $c['v'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,6 +655,11 @@ class Libzot {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if (empty($arr['primary_location']['address'])) {
|
||||
logger('Empty primary location address: ' . print_r($arr, true), LOGGER_DEBUG);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hooks import_xchan
|
||||
* Called when processing the result of zot_finger() to store the result
|
||||
@@ -1164,10 +1169,6 @@ class Libzot {
|
||||
$raw_activity = $AS->data;
|
||||
|
||||
$AS = new ActivityStreams($raw_activity['object'], portable_id: $env['sender']);
|
||||
|
||||
// Store the original activity id and type for later usage
|
||||
$AS->meta['original_id'] = $original_id;
|
||||
$AS->meta['original_type'] = $original_type;
|
||||
}
|
||||
|
||||
if (is_array($AS->obj)) {
|
||||
@@ -1541,6 +1542,7 @@ class Libzot {
|
||||
|
||||
$local_public = $public;
|
||||
$item_result = null;
|
||||
$parent = null;
|
||||
|
||||
$DR = new DReport(z_root(), $sender, $d, $arr['mid'], $arr['uuid']);
|
||||
|
||||
@@ -1556,7 +1558,7 @@ class Libzot {
|
||||
|
||||
$conversation_operation = $is_collection_operation && isset($arr['target']['attributedTo']);
|
||||
|
||||
if (str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
|
||||
if (isset($arr['tgt_type']) && str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
|
||||
$DR->update('not a collection activity');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
@@ -1848,19 +1850,12 @@ class Libzot {
|
||||
dbesc($arr['author_xchan'])
|
||||
);
|
||||
|
||||
// If we import an add/remove activity ($is_collection_operation) we strip off the
|
||||
// add/remove part and only process the object.
|
||||
// When looking up the item to pass it to the notifier for relay, we need to look up
|
||||
// the original (stripped off) message id which we stored in $act->meta.
|
||||
|
||||
$sql_mid = (($is_collection_operation && $relay && $channel['channel_hash'] === $arr['owner_xchan']) ? $act->meta['original_id'] : $arr['mid']);
|
||||
|
||||
// Reactions such as like and dislike could have an mid with /activity/ in it.
|
||||
// Check for both forms in order to prevent duplicates.
|
||||
|
||||
$r = q("select * from item where mid in ('%s', '%s') and uid = %d limit 1",
|
||||
dbesc($sql_mid),
|
||||
dbesc(reverse_activity_mid($sql_mid)),
|
||||
dbesc($arr['mid']),
|
||||
dbesc(reverse_activity_mid($arr['mid'])),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
@@ -2002,7 +1997,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
$DR->addto_update('relayed');
|
||||
$result[] = $DR->get();
|
||||
$result = [$DR->get()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,17 +8,18 @@ class MessageFilter {
|
||||
|
||||
public static function evaluate($item, $incl, $excl) {
|
||||
|
||||
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
|
||||
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
|
||||
$text = prepare_text($item['body'], ((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
|
||||
$text = html2plain((!empty($item['title'])) ? $item['title'] . ' ' . $text : $text);
|
||||
|
||||
$lang = null;
|
||||
|
||||
if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) {
|
||||
$lang = detect_language($text);
|
||||
}
|
||||
|
||||
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
|
||||
|
||||
$until = null;
|
||||
|
||||
// exclude always has priority
|
||||
|
||||
$exclude = (($excl) ? explode("\n", $excl) : null);
|
||||
@@ -41,7 +42,13 @@ class MessageFilter {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
elseif (str_starts_with($word, 'until=')) {
|
||||
$until = strtotime(trim(substr($word, 6)));
|
||||
if ($until > strtotime($item['created'] . ' UTC')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return false;
|
||||
@@ -89,7 +96,13 @@ class MessageFilter {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
elseif (str_starts_with($word, 'until=')) {
|
||||
$until = strtotime(trim(substr($word, 6)));
|
||||
if ($until > strtotime($item['created'] . ' UTC')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return true;
|
||||
@@ -124,9 +137,7 @@ class MessageFilter {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Test for Conditional Execution conditions. Shamelessly ripped off from Code/Render/Comanche
|
||||
*
|
||||
* This is extensible. The first version of variable testing supports tests of the forms:
|
||||
* Evaluate a conditional expression with support for AND (&&) and OR (||) operators.
|
||||
*
|
||||
* - ?foo ~= baz which will check if item.foo contains the string 'baz';
|
||||
* - ?foo == baz which will check if item.foo is the string 'baz';
|
||||
@@ -143,103 +154,110 @@ class MessageFilter {
|
||||
*
|
||||
* The values 0, '', an empty array, and an unset value will all evaluate to false.
|
||||
*
|
||||
* @param string $s
|
||||
* @param array $item
|
||||
* @return bool
|
||||
* @param string $s The condition string to evaluate.
|
||||
* @param array $item The associative array providing variable values.
|
||||
* @return bool True if the condition is met, false otherwise.
|
||||
*/
|
||||
|
||||
public static function test_condition($s,$item) {
|
||||
public static function test_condition($s, $item) {
|
||||
$s = trim($s);
|
||||
|
||||
// Handle OR (||)
|
||||
// Split on '||' not inside quotes
|
||||
$or_parts = preg_split('/\s*\|\|\s*/', $s);
|
||||
if (count($or_parts) > 1) {
|
||||
foreach ($or_parts as $part) {
|
||||
if (self::test_condition(ltrim($part, '?+'), $item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle AND (&&)
|
||||
// Split on '&&' not inside quotes
|
||||
$and_parts = preg_split('/\s*\&\&\s*/', $s);
|
||||
if (count($and_parts) > 1) {
|
||||
foreach ($and_parts as $part) {
|
||||
if (!self::test_condition(ltrim($part, '?+'), $item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Basic checks
|
||||
|
||||
// Contains substring (case-insensitive)
|
||||
if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (stripos($x, trim($matches[2])) !== false) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return (stripos($x, trim($matches[2])) !== false);
|
||||
}
|
||||
|
||||
// Equality
|
||||
if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x == trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x == trim($matches[2]));
|
||||
}
|
||||
|
||||
// Inequality
|
||||
if (preg_match('/(.*?)\s\!\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x != trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x != trim($matches[2]));
|
||||
}
|
||||
|
||||
// Greater than or equal
|
||||
if (preg_match('/(.*?)\s\>\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x >= trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x >= trim($matches[2]));
|
||||
}
|
||||
|
||||
// Less than or equal
|
||||
if (preg_match('/(.*?)\s\<\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x <= trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x <= trim($matches[2]));
|
||||
}
|
||||
|
||||
// Greater than
|
||||
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x > trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x > trim($matches[2]));
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x < trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// Less than
|
||||
if (preg_match('/(.*?)\s\<\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return ($x < trim($matches[2]));
|
||||
}
|
||||
|
||||
if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (is_array($x) && in_array(trim($matches[2]), $x)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// Array contains value
|
||||
if (preg_match('/(.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return (is_array($x) && in_array(trim($matches[2]), $x));
|
||||
}
|
||||
|
||||
// Array contains key
|
||||
if (preg_match('/(.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (is_array($x) && array_key_exists(trim($matches[2]), $x)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return (is_array($x) && array_key_exists(trim($matches[2]), $x));
|
||||
}
|
||||
|
||||
// Ordering of this check (for falsiness) with relation to the following one (check for truthiness) is important.
|
||||
// Falsy check
|
||||
if (preg_match('/\!(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (!$x) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return !$x;
|
||||
}
|
||||
|
||||
// Truthy check (default)
|
||||
if (preg_match('/(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
return (bool)$x;
|
||||
}
|
||||
|
||||
// If no conditions matched, return false
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -21,4 +21,13 @@ class Text {
|
||||
return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false);
|
||||
}
|
||||
|
||||
public static function rawurlencode_parts(string $string): string {
|
||||
if (!$string) {
|
||||
return EMPTY_STR;
|
||||
}
|
||||
|
||||
return implode('/', array_map('rawurlencode', explode('/', $string)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Access\AccessList;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once('include/text.php');
|
||||
|
||||
@@ -26,6 +24,7 @@ class ThreadItem {
|
||||
private $parent = null;
|
||||
private $conversation = null;
|
||||
private $redirect_url = null;
|
||||
private $owner_addr = '';
|
||||
private $owner_url = '';
|
||||
private $owner_photo = '';
|
||||
private $owner_name = '';
|
||||
@@ -35,14 +34,12 @@ class ThreadItem {
|
||||
private $channel = null;
|
||||
private $display_mode = 'normal';
|
||||
private $reload = '';
|
||||
private $mid_uuid_map = [];
|
||||
|
||||
|
||||
public function __construct($data) {
|
||||
|
||||
$this->data = $data;
|
||||
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
|
||||
$this->threaded = Config::Get('system','thread_allow');
|
||||
$this->threaded = ((local_channel()) ? PConfig::Get(local_channel(), 'system', 'thread_allow', true) : Config::Get('system', 'thread_allow', true));
|
||||
|
||||
// Prepare the children
|
||||
if(isset($data['children'])) {
|
||||
@@ -65,8 +62,6 @@ class ThreadItem {
|
||||
unset($this->data['children']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// allow a site to configure the order and content of the reaction emoji list
|
||||
if($this->toplevel) {
|
||||
$x = Config::Get('system','reactions');
|
||||
@@ -84,7 +79,7 @@ class ThreadItem {
|
||||
* _ false on failure
|
||||
*/
|
||||
|
||||
public function get_template_data($conv_responses, $mid_uuid_map, $thread_level=1, $conv_flags = []) {
|
||||
public function get_template_data($thread_level=1, $conv_flags = []) {
|
||||
|
||||
$result = [];
|
||||
$item = $this->get_data();
|
||||
@@ -103,6 +98,8 @@ class ThreadItem {
|
||||
$conv = $this->get_conversation();
|
||||
$observer = $conv->get_observer();
|
||||
|
||||
$conv->mid_uuid_map[$item['mid']] = $item['uuid'];
|
||||
|
||||
$acl = new AccessList([]);
|
||||
$acl->set($item);
|
||||
|
||||
@@ -114,7 +111,7 @@ class ThreadItem {
|
||||
$locktype = intval($item['item_private']);
|
||||
|
||||
if ($locktype === 2) {
|
||||
$lock = t('Direct message');
|
||||
$lock = t('Private message');
|
||||
}
|
||||
|
||||
// 0 = limited based on public policy
|
||||
@@ -209,9 +206,9 @@ class ThreadItem {
|
||||
}
|
||||
|
||||
if (in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
|
||||
$response_verbs[] = 'attendyes';
|
||||
$response_verbs[] = 'attendno';
|
||||
$response_verbs[] = 'attendmaybe';
|
||||
$response_verbs[] = 'accept';
|
||||
$response_verbs[] = 'reject';
|
||||
$response_verbs[] = 'tentativeaccept';
|
||||
if($this->is_commentable() && $observer) {
|
||||
$isevent = true;
|
||||
$attend = array( t('I will attend'), t('I will not attend'), t('I might attend'));
|
||||
@@ -222,17 +219,8 @@ class ThreadItem {
|
||||
$response_verbs[] = 'answer';
|
||||
}
|
||||
|
||||
if (!feature_enabled($conv->get_profile_owner(),'dislike')) {
|
||||
unset($conv_responses['dislike']);
|
||||
}
|
||||
|
||||
$responses = get_responses($conv_responses,$response_verbs,$this,$item);
|
||||
|
||||
$my_responses = [];
|
||||
foreach($response_verbs as $v) {
|
||||
$my_responses[$v] = ((isset($conv_responses[$v][$item['mid'] . '-m'])) ? 1 : 0);
|
||||
}
|
||||
|
||||
$response_verbs[] = 'comment';
|
||||
$responses = get_responses($response_verbs, $item);
|
||||
|
||||
/*
|
||||
* We should avoid doing this all the time, but it depends on the conversation mode
|
||||
@@ -242,7 +230,13 @@ class ThreadItem {
|
||||
|
||||
$this->check_wall_to_wall();
|
||||
|
||||
$children = $this->get_children();
|
||||
$children_count = count($children);
|
||||
|
||||
if($this->is_toplevel()) {
|
||||
$conv->comments_total = $responses['comment']['count'] ?? 0;
|
||||
$conv->comments_loaded = $children_count;
|
||||
|
||||
if((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) {
|
||||
$star = [
|
||||
'toggle' => t("Toggle Star Status"),
|
||||
@@ -254,7 +248,6 @@ class ThreadItem {
|
||||
$is_comment = true;
|
||||
}
|
||||
|
||||
|
||||
$verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
|
||||
$forged = ((($item['sig']) && (! intval($item['item_verified']))) ? t('Message signature incorrect') : '');
|
||||
$unverified = '' ; // (($this->is_wall_to_wall() && (! intval($item['item_verified']))) ? t('Message cannot be verified') : '');
|
||||
@@ -287,15 +280,11 @@ class ThreadItem {
|
||||
if((in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) && $conv->get_profile_owner() == local_channel())
|
||||
$has_event = true;
|
||||
|
||||
$like = [];
|
||||
$dislike = [];
|
||||
$reply_to = [];
|
||||
$reactions_allowed = false;
|
||||
|
||||
if($this->is_commentable() && $observer) {
|
||||
$like = array( t("I like this \x28toggle\x29"), t("like"));
|
||||
$dislike = array( t("I don't like this \x28toggle\x29"), t("dislike"));
|
||||
$reply_to = array( t("Reply to this comment"), t("reply"), t("Reply to"));
|
||||
$reply_to = array( t("Reply to this message"), t("reply"), t("Reply to"));
|
||||
$reactions_allowed = true;
|
||||
}
|
||||
|
||||
@@ -339,9 +328,8 @@ class ThreadItem {
|
||||
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
|
||||
|
||||
$comment_count_txt = ['label' => sprintf(tt('%d comment', '%d comments', $total_children), $total_children), 'count' => $total_children];
|
||||
$list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : [];
|
||||
|
||||
$children = $this->get_children();
|
||||
$list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : [];
|
||||
|
||||
$has_tags = (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false);
|
||||
|
||||
@@ -351,14 +339,7 @@ class ThreadItem {
|
||||
|
||||
$midb64 = $item['uuid'];
|
||||
$mids = [ $item['uuid'] ];
|
||||
$response_mids = [];
|
||||
foreach($response_verbs as $v) {
|
||||
if(isset($conv_responses[$v]['mids'][$item['mid']])) {
|
||||
$response_mids = array_merge($response_mids, $conv_responses[$v]['mids'][$item['mid']]);
|
||||
}
|
||||
}
|
||||
|
||||
$mids = array_merge($mids, $response_mids);
|
||||
$json_mids = json_encode($mids);
|
||||
|
||||
// Pinned item processing
|
||||
@@ -372,6 +353,22 @@ class ThreadItem {
|
||||
$contact = App::$contacts[$item['author_xchan']];
|
||||
}
|
||||
|
||||
$blog_mode = $this->get_display_mode() === 'list';
|
||||
$load_more = false;
|
||||
$load_more_title = '';
|
||||
$comments_total_percent = 0;
|
||||
if (($conv->comments_total > $conv->comments_loaded) || ($blog_mode && $conv->comments_total > 3)) {
|
||||
// provide a load more comments button
|
||||
$load_more = true;
|
||||
$load_more_title = sprintf(t('Load the next few of total %d comments'), $conv->comments_total);
|
||||
$comments_total_percent = round(100 * 3 / $conv->comments_total);
|
||||
}
|
||||
|
||||
$expand = '';
|
||||
if ($this->threaded && !empty($item['comment_count'] && !$this->is_toplevel())) {
|
||||
$expand = t('Expand Replies');
|
||||
}
|
||||
|
||||
$tmp_item = array(
|
||||
'template' => $this->get_template(),
|
||||
'mode' => $mode,
|
||||
@@ -384,9 +381,9 @@ class ThreadItem {
|
||||
'folders' => $body['folders'],
|
||||
'text' => strip_tags($body['html']),
|
||||
'id' => $this->get_id(),
|
||||
'parent' => $item['parent'],
|
||||
'mid' => $midb64,
|
||||
'mids' => $json_mids,
|
||||
'parent' => $item['parent'],
|
||||
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
||||
'author_is_group_actor' => (($item['author']['xchan_pubforum']) ? t('Forum') : ''),
|
||||
'isevent' => $isevent,
|
||||
@@ -431,6 +428,7 @@ class ThreadItem {
|
||||
'vote_title' => t('Voting Options'),
|
||||
'is_comment' => $is_comment,
|
||||
'is_new' => $is_new,
|
||||
'owner_addr' => $this->get_owner_addr(),
|
||||
'owner_url' => $this->get_owner_url(),
|
||||
'owner_photo' => $this->get_owner_photo(),
|
||||
'owner_name' => $this->get_owner_name(),
|
||||
@@ -440,13 +438,12 @@ class ThreadItem {
|
||||
'reactions' => $this->reactions,
|
||||
// Item toolbar buttons
|
||||
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
|
||||
'like' => $like,
|
||||
'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
|
||||
'reply_to' => (((! $this->is_toplevel()) && feature_enabled($conv->get_profile_owner(),'reply_to')) ? $reply_to : ''),
|
||||
'reply_to' => ((feature_enabled($conv->get_profile_owner(),'reply_to')) ? $reply_to : ''),
|
||||
'top_hint' => t("Go to previous comment"),
|
||||
'share' => $share,
|
||||
'embed' => $embed,
|
||||
'rawmid' => $item['mid'],
|
||||
'parent_mid' => $item['parent_mid'],
|
||||
'plink' => get_plink($item),
|
||||
'edpost' => $edpost,
|
||||
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts') && ($item['item_type'] == ITEM_TYPE_POST)) ? $star : ''),
|
||||
@@ -466,16 +463,17 @@ class ThreadItem {
|
||||
'list_unseen_txt' => $list_unseen_txt,
|
||||
'markseen' => t('Mark all comments seen'),
|
||||
'responses' => $responses,
|
||||
'my_responses' => $my_responses,
|
||||
// 'my_responses' => $my_responses,
|
||||
'modal_dismiss' => t('Close'),
|
||||
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()),
|
||||
'comment_hidden' => feature_enabled($conv->get_profile_owner(),'reply_to'),
|
||||
'no_comment' => (($item['item_thread_top'] && $item['item_nocomment'])? t('Comments disabled') : ''),
|
||||
'previewing' => ($conv->is_preview() ? true : false ),
|
||||
'preview_lbl' => t('This is an unsaved preview'),
|
||||
'wait' => t('Please wait'),
|
||||
'thread_level' => $thread_level,
|
||||
'settings' => $settings,
|
||||
'thr_parent_uuid' => (($item['parent_mid'] != $item['thr_parent']) ? $mid_uuid_map[$item['thr_parent']] : ''),
|
||||
'thr_parent_uuid' => (($item['parent_mid'] !== $item['thr_parent'] && isset($conv->mid_uuid_map[$item['thr_parent']])) ? $conv->mid_uuid_map[$item['thr_parent']] : ''),
|
||||
'contact_id' => (($contact) ? $contact['abook_id'] : ''),
|
||||
'moderate' => ($item['item_blocked'] == ITEM_MODERATED),
|
||||
'moderate_approve' => t('Approve'),
|
||||
@@ -483,7 +481,25 @@ class ThreadItem {
|
||||
'rtl' => in_array($item['lang'], rtl_languages()),
|
||||
'reactions_allowed' => $reactions_allowed,
|
||||
'reaction_str' => [t('Add yours'), t('Remove yours')],
|
||||
'is_contained' => $this->is_toplevel() && str_contains($item['tgt_type'], 'Collection')
|
||||
'is_contained' => $this->is_toplevel() && str_contains($item['tgt_type'], 'Collection'),
|
||||
'observer_activity' => [
|
||||
'like' => intval($item['observer_like_count'] ?? 0),
|
||||
'dislike' => intval($item['observer_dislike_count'] ?? 0),
|
||||
'announce' => intval($item['observer_announce_count'] ?? 0),
|
||||
'comment' => intval($item['observer_comment_count'] ?? 0),
|
||||
'accept' => intval($item['observer_accept_count'] ?? 0),
|
||||
'reject' => intval($item['observer_reject_count'] ?? 0),
|
||||
'tentativeaccept' => intval($item['observer_tentativeaccept_count'] ?? 0)
|
||||
],
|
||||
'threaded' => $this->threaded,
|
||||
'blog_mode' => $blog_mode,
|
||||
'collapse_comments' => t('show less'),
|
||||
'expand_comments' => $this->threaded ? t('show more') : t('show all'),
|
||||
'load_more' => $load_more,
|
||||
'load_more_title' => $load_more_title,
|
||||
'comments_total' => $conv->comments_total,
|
||||
'comments_total_percent' => $comments_total_percent,
|
||||
'expand' => $expand
|
||||
);
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
@@ -492,25 +508,19 @@ class ThreadItem {
|
||||
$result = $arr['output'];
|
||||
|
||||
$result['children'] = array();
|
||||
$nb_children = count($children);
|
||||
|
||||
$visible_comments = Config::Get('system', 'expanded_comments', 3);
|
||||
$visible_comments = 3; // Config::Get('system', 'expanded_comments', 3);
|
||||
|
||||
if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
|
||||
if(($this->get_display_mode() === 'normal') && ($children_count > 0)) {
|
||||
foreach($children as $child) {
|
||||
$result['children'][] = $child->get_template_data($conv_responses, $mid_uuid_map, $thread_level + 1,$conv_flags);
|
||||
$result['children'][] = $child->get_template_data($thread_level + 1, $conv_flags);
|
||||
}
|
||||
|
||||
// Collapse
|
||||
if(($nb_children > $visible_comments) || ($thread_level > 1)) {
|
||||
if($thread_level === 1 && $children_count > $visible_comments) {
|
||||
$result['children'][0]['comment_firstcollapsed'] = true;
|
||||
$result['children'][0]['num_comments'] = $comment_count_txt['label'];
|
||||
$result['children'][0]['hide_text'] = t('show all');
|
||||
if($thread_level > 1) {
|
||||
$result['children'][$nb_children - 1]['comment_lastcollapsed'] = true;
|
||||
}
|
||||
else {
|
||||
$result['children'][$nb_children - ($visible_comments + 1)]['comment_lastcollapsed'] = true;
|
||||
}
|
||||
$result['children'][$children_count - ($visible_comments + 1)]['comment_lastcollapsed'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,7 +773,7 @@ class ThreadItem {
|
||||
*/
|
||||
private function get_comment_box() {
|
||||
|
||||
if(!$this->is_toplevel() && !Config::Get('system','thread_allow')) {
|
||||
if(!$this->is_toplevel()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -799,10 +809,11 @@ class ThreadItem {
|
||||
'$submit' => t('Submit'),
|
||||
'$edbold' => t('Bold'),
|
||||
'$editalic' => t('Italic'),
|
||||
'$edhighlighter' => t('Highlight selected text'),
|
||||
'$eduline' => t('Underline'),
|
||||
'$edquote' => t('Quote'),
|
||||
'$edcode' => t('Code'),
|
||||
'$edimg' => t('Image'),
|
||||
'$edimg' => t('Embed (existing) photo from your photo albums'),
|
||||
'$edatt' => t('Attach/Upload file'),
|
||||
'$edurl' => t('Insert Link'),
|
||||
'$edvideo' => t('Video'),
|
||||
@@ -833,6 +844,7 @@ class ThreadItem {
|
||||
$conv = $this->get_conversation();
|
||||
$this->wall_to_wall = false;
|
||||
$this->owner_url = '';
|
||||
$this->owner_addr = '';
|
||||
$this->owner_photo = '';
|
||||
$this->owner_name = '';
|
||||
|
||||
@@ -841,12 +853,14 @@ class ThreadItem {
|
||||
|
||||
if($this->is_toplevel() && ($this->get_data_value('author_xchan') != $this->get_data_value('owner_xchan'))) {
|
||||
$this->owner_url = chanlink_hash($this->data['owner']['xchan_hash']);
|
||||
$this->owner_addr = $this->data['owner']['xchan_addr'];
|
||||
$this->owner_photo = $this->data['owner']['xchan_photo_s'];
|
||||
$this->owner_name = $this->data['owner']['xchan_name'];
|
||||
$this->wall_to_wall = true;
|
||||
}
|
||||
elseif($this->is_toplevel() && $this->get_data_value('verb') === 'Announce' && isset($this->data['source'])) {
|
||||
$this->owner_url = chanlink_hash($this->data['source']['xchan_hash']);
|
||||
$this->owner_addr = $this->data['source']['xchan_addr'];
|
||||
$this->owner_photo = $this->data['source']['xchan_photo_s'];
|
||||
$this->owner_name = $this->data['source']['xchan_name'];
|
||||
$this->wall_to_wall = true;
|
||||
@@ -861,6 +875,10 @@ class ThreadItem {
|
||||
return $this->owner_url;
|
||||
}
|
||||
|
||||
private function get_owner_addr() {
|
||||
return $this->owner_addr;
|
||||
}
|
||||
|
||||
private function get_owner_photo() {
|
||||
return $this->owner_photo;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ class ThreadStream {
|
||||
private $prepared_item = '';
|
||||
public $reload = '';
|
||||
private $cipher = 'AES-128-CCM';
|
||||
public $mid_uuid_map = [];
|
||||
public $comments_total = 0;
|
||||
public $comments_loaded = 0;
|
||||
|
||||
|
||||
// $prepared_item is for use by alternate conversation structures such as photos
|
||||
// wherein we've already prepared a top level item which doesn't look anything like
|
||||
@@ -211,16 +215,15 @@ class ThreadStream {
|
||||
* _ The data requested on success
|
||||
* _ false on failure
|
||||
*/
|
||||
public function get_template_data($conv_responses, $mid_uuid_map) {
|
||||
public function get_template_data() {
|
||||
$result = array();
|
||||
|
||||
foreach($this->threads as $item) {
|
||||
|
||||
if(($item->get_data_value('id') == $item->get_data_value('parent')) && $this->prepared_item) {
|
||||
$item_data = $this->prepared_item;
|
||||
}
|
||||
else {
|
||||
$item_data = $item->get_template_data($conv_responses, $mid_uuid_map);
|
||||
$item_data = $item->get_template_data();
|
||||
}
|
||||
if(!$item_data) {
|
||||
logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR);
|
||||
|
||||
@@ -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,14 +23,14 @@ class Activity extends Controller {
|
||||
if (! $item_id)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$portable_id = EMPTY_STR;
|
||||
$portable_id = null;
|
||||
|
||||
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
|
||||
dbesc(ACTIVITY_FOLLOW),
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -166,6 +166,7 @@ class Activity extends Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$portable_id = null;
|
||||
$ob_authorize = false;
|
||||
$item_uid = 0;
|
||||
|
||||
@@ -191,7 +192,7 @@ class Activity extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
|
||||
@@ -133,6 +133,11 @@ class Attach_edit extends Controller {
|
||||
}
|
||||
$x = attach_move($channel_id, $resource, $newfolder, (($single) ? $newfilename : ''));
|
||||
|
||||
if (!$x['success']) {
|
||||
notice($x['message'] . EOL);
|
||||
goaway($return_path);
|
||||
}
|
||||
|
||||
$actions_done .= 'move,';
|
||||
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class Channel extends Controller {
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'Digest' => HTTPSig::generate_digest_header($data),
|
||||
'(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']
|
||||
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T')
|
||||
];
|
||||
|
||||
$h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel));
|
||||
@@ -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();
|
||||
|
||||
@@ -30,7 +30,7 @@ class Conversation extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -83,9 +83,9 @@ class Conversation extends Controller {
|
||||
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
|
||||
// with a bias towards those items owned by channels on this site (item_wall = 1)
|
||||
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
if (!$i) {
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
|
||||
dbesc($r[0]['parent_mid'])
|
||||
);
|
||||
|
||||
@@ -81,7 +81,7 @@ class Display extends Controller {
|
||||
'default_location' => $channel['channel_location'],
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'member/permissions'),
|
||||
'permissions' => $channel_acl,
|
||||
'bang' => '',
|
||||
'visitor' => true,
|
||||
@@ -212,7 +212,7 @@ class Display extends Controller {
|
||||
$observer_hash = get_observer_hash();
|
||||
$item_normal = item_normal();
|
||||
$item_normal_update = item_normal_update();
|
||||
$sql_extra = '';
|
||||
$permission_sql = '';
|
||||
$r = [];
|
||||
|
||||
if($noscript_content || $load) {
|
||||
@@ -231,7 +231,7 @@ class Display extends Controller {
|
||||
}
|
||||
|
||||
if(!$r) {
|
||||
$sql_extra = item_permissions_sql(0, $observer_hash);
|
||||
$permission_sql = item_permissions_sql(0, $observer_hash);
|
||||
|
||||
$r = q("SELECT item.id AS item_id FROM item
|
||||
WHERE ((mid = '%s'
|
||||
@@ -239,7 +239,7 @@ class Display extends Controller {
|
||||
AND item.deny_gid = '' AND item_private = 0 )
|
||||
AND uid IN ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
|
||||
OR uid = %d ))) OR
|
||||
(mid = '%s' $sql_extra ))
|
||||
(mid = '%s' $permission_sql ))
|
||||
$item_normal
|
||||
limit 1",
|
||||
dbesc($target_item['parent_mid']),
|
||||
@@ -269,7 +269,7 @@ class Display extends Controller {
|
||||
}
|
||||
|
||||
if(!$r) {
|
||||
$sql_extra = item_permissions_sql(0, $observer_hash);
|
||||
$permission_sql = item_permissions_sql(0, $observer_hash);
|
||||
|
||||
$r = q("SELECT item.id as item_id from item
|
||||
WHERE ((parent_mid = '%s'
|
||||
@@ -277,7 +277,7 @@ class Display extends Controller {
|
||||
AND item.deny_gid = '' AND item_private = 0 )
|
||||
and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
|
||||
OR uid = %d ))) OR
|
||||
(parent_mid = '%s' $sql_extra ))
|
||||
(parent_mid = '%s' $permission_sql ))
|
||||
$item_normal
|
||||
limit 1",
|
||||
dbesc($target_item['parent_mid']),
|
||||
@@ -288,17 +288,12 @@ class Display extends Controller {
|
||||
}
|
||||
|
||||
if($r) {
|
||||
$parents_str = ids_to_querystr($r,'item_id');
|
||||
if($parents_str) {
|
||||
$items = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE parent in ( %s ) $sql_extra $item_normal ",
|
||||
dbesc($parents_str)
|
||||
);
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items,true);
|
||||
$items = conv_sort($items,'created');
|
||||
}
|
||||
$thr_parents = get_recursive_thr_parents($target_item);
|
||||
$items = items_by_parent_ids($r, $thr_parents, $permission_sql);
|
||||
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items,true);
|
||||
$items = conv_sort($items,'created');
|
||||
}
|
||||
else {
|
||||
$items = array();
|
||||
|
||||
@@ -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);
|
||||
@@ -100,14 +104,25 @@ class Home extends Controller {
|
||||
goaway($frontpage);
|
||||
}
|
||||
|
||||
$o .= '<div class="generic-content-wrapper">';
|
||||
|
||||
$sitename = Config::Get('system', 'sitename');
|
||||
if ($sitename)
|
||||
$o .= '<h1 class="home-welcome">' . sprintf(t('Welcome to %s'), $sitename) . '</h1>';
|
||||
if ($sitename) {
|
||||
$o .= '<div class="section-title-wrapper">';
|
||||
$o .= '<h2 class="">' . sprintf(t('Welcome to %s'), $sitename) . '</h2>';
|
||||
$o .= '</div>';
|
||||
|
||||
}
|
||||
|
||||
$o .= '<div class="section-content-wrapper">';
|
||||
|
||||
$loginbox = Config::Get('system', 'login_on_homepage');
|
||||
if (intval($loginbox) || $loginbox === false)
|
||||
$o .= login(true);
|
||||
|
||||
$o .= '</div>';
|
||||
$o .= '</div>';
|
||||
|
||||
return $o;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Widget\Messages;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Hq extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -50,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();
|
||||
}
|
||||
@@ -383,6 +384,7 @@ class Item extends Controller {
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($channel['channel_hash'])
|
||||
);
|
||||
|
||||
if ($r && count($r)) {
|
||||
$owner_xchan = $r[0];
|
||||
}
|
||||
@@ -390,7 +392,7 @@ class Item extends Controller {
|
||||
logger("mod_item: no owner.");
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'no owner']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -424,17 +426,21 @@ class Item extends Controller {
|
||||
$view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'view_stream');
|
||||
$comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'post_comments');
|
||||
|
||||
$public_policy = ((x($_REQUEST, 'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy, true));
|
||||
if ($webpage)
|
||||
$public_policy = '';
|
||||
if ($public_policy)
|
||||
$public_policy = '';
|
||||
|
||||
if (intval($item_type) === ITEM_TYPE_POST) {
|
||||
$public_policy = ((!empty($_POST['public_policy'])) ? escape_tags($_POST['public_policy']) : map_scope($view_policy, true));
|
||||
}
|
||||
|
||||
if ($public_policy) {
|
||||
$private = 1;
|
||||
}
|
||||
|
||||
if ($orig_post) {
|
||||
$private = 0;
|
||||
// webpages are allowed to change ACLs after the fact. Normal conversation items aren't.
|
||||
if ($webpage) {
|
||||
$acl->set_from_array($_REQUEST);
|
||||
// Normal conversation items are not allowed to change ACL.
|
||||
if (intval($item_type) !== ITEM_TYPE_POST) {
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
else {
|
||||
$acl->set($orig_post);
|
||||
@@ -450,9 +456,9 @@ class Item extends Controller {
|
||||
$coord = $orig_post['coord'];
|
||||
$verb = $orig_post['verb'];
|
||||
$app = $orig_post['app'];
|
||||
$title = escape_tags(trim($_REQUEST['title']));
|
||||
$summary = escape_tags(trim($_REQUEST['summary']));
|
||||
$body = trim($_REQUEST['body']);
|
||||
$title = escape_tags(trim($_POST['title']));
|
||||
$summary = escape_tags(trim($_POST['summary']));
|
||||
$body = trim($_POST['body']);
|
||||
$item_flags = $orig_post['item_flags'];
|
||||
$item_origin = $orig_post['item_origin'];
|
||||
$item_unseen = $orig_post['item_unseen'];
|
||||
@@ -486,14 +492,15 @@ class Item extends Controller {
|
||||
$thr_parent = $orig_post['thr_parent'];
|
||||
$parent_mid = $orig_post['parent_mid'];
|
||||
$plink = $orig_post['plink'];
|
||||
$owner_hash = $orig_post['owner_xchan'];
|
||||
}
|
||||
else {
|
||||
if (!$walltowall) {
|
||||
if ((array_key_exists('contact_allow', $_REQUEST))
|
||||
|| (array_key_exists('group_allow', $_REQUEST))
|
||||
|| (array_key_exists('contact_deny', $_REQUEST))
|
||||
|| (array_key_exists('group_deny', $_REQUEST))) {
|
||||
$acl->set_from_array($_REQUEST);
|
||||
if ((array_key_exists('contact_allow', $_POST))
|
||||
|| (array_key_exists('group_allow', $_POST))
|
||||
|| (array_key_exists('contact_deny', $_POST))
|
||||
|| (array_key_exists('group_deny', $_POST))) {
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
elseif (!$api_source) {
|
||||
|
||||
@@ -508,16 +515,16 @@ class Item extends Controller {
|
||||
}
|
||||
|
||||
|
||||
$location = ((isset($_REQUEST['location'])) ? notags(trim($_REQUEST['location'])) : '');
|
||||
$coord = ((isset($_REQUEST['coord'])) ? notags(trim($_REQUEST['coord'])) : '');
|
||||
$verb = ((isset($_REQUEST['verb'])) ? notags(trim($_REQUEST['verb'])) : '');
|
||||
$title = ((isset($_REQUEST['title'])) ? escape_tags(trim($_REQUEST['title'])) : '');
|
||||
$summary = ((isset($_REQUEST['summary'])) ? escape_tags(trim($_REQUEST['summary'])) : '');
|
||||
$body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : '');
|
||||
$body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : '');
|
||||
$location = ((isset($_POST['location'])) ? notags(trim($_POST['location'])) : '');
|
||||
$coord = ((isset($_POST['coord'])) ? notags(trim($_POST['coord'])) : '');
|
||||
$verb = ((isset($_POST['verb'])) ? notags(trim($_POST['verb'])) : '');
|
||||
$title = ((isset($_POST['title'])) ? escape_tags(trim($_POST['title'])) : '');
|
||||
$summary = ((isset($_POST['summary'])) ? escape_tags(trim($_POST['summary'])) : '');
|
||||
$body = ((isset($_POST['body'])) ? trim($_POST['body']) : '');
|
||||
$body .= ((isset($_POST['attachment'])) ? trim($_POST['attachment']) : '');
|
||||
$postopts = '';
|
||||
|
||||
$allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
|
||||
$allow_empty = ((array_key_exists('allow_empty', $_POST)) ? intval($_POST['allow_empty']) : 0);
|
||||
|
||||
$private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy)));
|
||||
|
||||
@@ -528,7 +535,7 @@ class Item extends Controller {
|
||||
$private = intval($parent_item['item_private']);
|
||||
$public_policy = $parent_item['public_policy'];
|
||||
$owner_hash = $parent_item['owner_xchan'];
|
||||
$webpage = $parent_item['item_type'];
|
||||
$item_type = $parent_item['item_type'];
|
||||
}
|
||||
|
||||
|
||||
@@ -539,7 +546,7 @@ class Item extends Controller {
|
||||
info(t('Empty post discarded.') . EOL);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'no content']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -547,15 +554,15 @@ class Item extends Controller {
|
||||
|
||||
|
||||
if (feature_enabled($profile_uid, 'content_expire')) {
|
||||
if (x($_REQUEST, 'expire')) {
|
||||
$expires = datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['expire']);
|
||||
if (!empty($_POST['expire'])) {
|
||||
$expires = datetime_convert(date_default_timezone_get(), 'UTC', $_POST['expire']);
|
||||
if ($expires <= datetime_convert())
|
||||
$expires = NULL_DATE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$mimetype = ((isset($_REQUEST['mimetype'])) ? notags(trim($_REQUEST['mimetype'])) : '');
|
||||
$mimetype = ((isset($_POST['mimetype'])) ? notags(trim($_POST['mimetype'])) : '');
|
||||
|
||||
if (!$mimetype)
|
||||
$mimetype = 'text/bbcode';
|
||||
@@ -589,7 +596,7 @@ class Item extends Controller {
|
||||
|
||||
$is_group = get_pconfig($profile_uid, 'system', 'group_actor');
|
||||
|
||||
if ($is_group && $walltowall && !$walltowall_comment && !$webpage) {
|
||||
if ($is_group && $walltowall && !$walltowall_comment && (intval($item_type) === ITEM_TYPE_POST)) {
|
||||
$groupww = true;
|
||||
$str_contact_allow = $owner_xchan['xchan_hash'];
|
||||
$str_group_allow = '';
|
||||
@@ -788,7 +795,7 @@ class Item extends Controller {
|
||||
}
|
||||
|
||||
$item_unseen = ((local_channel() != $profile_uid) ? 1 : 0);
|
||||
$item_wall = ((isset($_REQUEST['type']) && ($_REQUEST['type'] === 'wall' || $_REQUEST['type'] === 'wall-comment')) ? 1 : 0);
|
||||
$item_wall = ((isset($_POST['type']) && ($_POST['type'] === 'wall' || $_POST['type'] === 'wall-comment')) ? 1 : 0);
|
||||
$item_origin = (($origin) ? 1 : 0);
|
||||
$item_consensus = (($consensus) ? 1 : 0);
|
||||
$item_nocomment = (($nocomment) ? 1 : 0);
|
||||
@@ -796,15 +803,13 @@ class Item extends Controller {
|
||||
|
||||
// determine if this is a wall post
|
||||
|
||||
if (in_array($item_type, [ITEM_TYPE_POST, ITEM_TYPE_CARD, ITEM_TYPE_ARTICLE])) {
|
||||
$item_wall = 1;
|
||||
}
|
||||
|
||||
if ($parent) {
|
||||
$item_wall = $parent_item['item_wall'];
|
||||
}
|
||||
else {
|
||||
if (!$webpage) {
|
||||
$item_wall = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($moderated) {
|
||||
$item_blocked = ITEM_MODERATED;
|
||||
@@ -821,36 +826,34 @@ class Item extends Controller {
|
||||
$mid = $mid ?? z_root() . '/item/' . $uuid;
|
||||
|
||||
|
||||
// Set the conversation target.
|
||||
if (empty($owner_hash)) {
|
||||
$owner_hash = $owner_xchan['xchan_hash'];
|
||||
}
|
||||
|
||||
if ($owner_hash === $channel['channel_hash']) {
|
||||
$attributedTo = z_root() . '/channel/' . $channel['channel_address'];
|
||||
|
||||
$conversation = isset($parent_item) ? $parent_item['mid'] : $mid;
|
||||
$datarray['target'] = [
|
||||
'id' => str_replace('/item/', '/conversation/', $conversation),
|
||||
'type' => 'Collection',
|
||||
'attributedTo' => $attributedTo,
|
||||
];
|
||||
$datarray['tgt_type'] = 'Collection';
|
||||
}
|
||||
elseif (!empty($parent_item['target'])) {
|
||||
$datarray['target'] = $parent_item['target'];
|
||||
$datarray['tgt_type'] = $parent_item['tgt_type'];
|
||||
}
|
||||
if (empty($owner_hash)) {
|
||||
$owner_hash = $owner_xchan['xchan_hash'];
|
||||
}
|
||||
|
||||
// Set the conversation target.
|
||||
if ($owner_hash === $channel['channel_hash']) {
|
||||
$attributedTo = z_root() . '/channel/' . $channel['channel_address'];
|
||||
|
||||
$conversation = isset($parent_item) ? $parent_item['mid'] : $mid;
|
||||
$datarray['target'] = [
|
||||
'id' => str_replace('/item/', '/conversation/', $conversation),
|
||||
'type' => 'Collection',
|
||||
'attributedTo' => $attributedTo,
|
||||
];
|
||||
$datarray['tgt_type'] = 'Collection';
|
||||
}
|
||||
elseif (!empty($parent_item['target'])) {
|
||||
$datarray['target'] = $parent_item['target'];
|
||||
$datarray['tgt_type'] = $parent_item['tgt_type'];
|
||||
}
|
||||
|
||||
if ($is_poll) {
|
||||
$poll = [
|
||||
'question' => $body,
|
||||
'answers' => $_REQUEST['poll_answers'],
|
||||
'multiple_answers' => $_REQUEST['poll_multiple_answers'],
|
||||
'expire_value' => $_REQUEST['poll_expire_value'],
|
||||
'expire_unit' => $_REQUEST['poll_expire_unit']
|
||||
'answers' => $_POST['poll_answers'],
|
||||
'multiple_answers' => $_POST['poll_multiple_answers'],
|
||||
'expire_value' => $_POST['poll_expire_value'],
|
||||
'expire_unit' => $_POST['poll_expire_unit']
|
||||
];
|
||||
$obj = $this->extract_poll_data($poll, ['item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny]);
|
||||
}
|
||||
@@ -885,19 +888,13 @@ class Item extends Controller {
|
||||
if ($parent_item)
|
||||
$parent_mid = $parent_item['mid'];
|
||||
|
||||
|
||||
// Fallback so that we always have a thr_parent
|
||||
|
||||
if (!$thr_parent)
|
||||
$thr_parent = $mid;
|
||||
|
||||
|
||||
$item_thread_top = ((!$parent) ? 1 : 0);
|
||||
|
||||
if ((!$plink) && ($item_thread_top)) {
|
||||
$plink = $mid;
|
||||
}
|
||||
|
||||
if (isset($datarray['obj']) && $datarray['obj']) {
|
||||
$datarray['obj']['id'] = $mid;
|
||||
}
|
||||
@@ -935,7 +932,7 @@ class Item extends Controller {
|
||||
$datarray['item_unseen'] = intval($item_unseen);
|
||||
$datarray['item_wall'] = intval($item_wall);
|
||||
$datarray['item_origin'] = intval($item_origin);
|
||||
$datarray['item_type'] = $webpage;
|
||||
$datarray['item_type'] = $item_type;
|
||||
$datarray['item_private'] = intval($private);
|
||||
$datarray['item_thread_top'] = intval($item_thread_top);
|
||||
$datarray['item_starred'] = intval($item_starred);
|
||||
@@ -960,7 +957,7 @@ class Item extends Controller {
|
||||
$datarray['public_policy'] = $public_policy;
|
||||
$datarray['comment_policy'] = map_scope($comment_policy);
|
||||
$datarray['term'] = array_unique($post_tags, SORT_REGULAR);
|
||||
$datarray['plink'] = $plink;
|
||||
$datarray['plink'] = $plink ?? $mid;
|
||||
$datarray['route'] = $route;
|
||||
|
||||
// A specific ACL over-rides public_policy completely
|
||||
@@ -1014,14 +1011,14 @@ class Item extends Controller {
|
||||
|
||||
call_hooks('post_local', $datarray);
|
||||
|
||||
if (x($datarray, 'cancel')) {
|
||||
if (!empty($datarray['cancel'])) {
|
||||
logger('mod_item: post cancelled by plugin or duplicate suppressed.');
|
||||
if ($return_path)
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'operation cancelled']);
|
||||
$json = ['cancel' => 1];
|
||||
$json['reload'] = z_root() . '/' . $_REQUEST['jsreload'];
|
||||
$json['reload'] = z_root() . '/' . $_POST['jsreload'];
|
||||
echo json_encode($json);
|
||||
killme();
|
||||
}
|
||||
@@ -1030,8 +1027,8 @@ class Item extends Controller {
|
||||
if (mb_strlen($datarray['title']) > 191)
|
||||
$datarray['title'] = mb_substr($datarray['title'], 0, 191);
|
||||
|
||||
if ($webpage) {
|
||||
IConfig::Set($datarray, 'system', webpage_to_namespace($webpage),
|
||||
if (intval($item_type) !== ITEM_TYPE_POST) {
|
||||
IConfig::Set($datarray, 'system', item_type_to_namespace($item_type),
|
||||
(($pagetitle) ? $pagetitle : basename($datarray['mid'])), true);
|
||||
}
|
||||
elseif ($namespace) {
|
||||
@@ -1071,7 +1068,7 @@ class Item extends Controller {
|
||||
if ($api_source)
|
||||
return ($x);
|
||||
|
||||
if ((x($_REQUEST, 'return')) && strlen($return_path)) {
|
||||
if ((!empty($_POST['return'])) && strlen($return_path)) {
|
||||
logger('return: ' . $return_path);
|
||||
|
||||
if ($return_path === 'hq') {
|
||||
@@ -1224,11 +1221,12 @@ class Item extends Controller {
|
||||
$json = [
|
||||
'success' => 1,
|
||||
'id' => $post_id,
|
||||
'thr_parent_id' => $thr_parent_id,
|
||||
'html' => conversation($item, $mode, true, 'r_preview'),
|
||||
];
|
||||
|
||||
if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload']))
|
||||
$json['reload'] = z_root() . '/' . $_REQUEST['jsreload'];
|
||||
if (!empty($_POST['jsreload']))
|
||||
$json['reload'] = z_root() . '/' . $_POST['jsreload'];
|
||||
|
||||
logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
|
||||
|
||||
@@ -1503,7 +1501,7 @@ class Item extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -1619,7 +1617,7 @@ class Item extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
|
||||
@@ -65,8 +65,22 @@ class Lang extends Controller {
|
||||
}
|
||||
|
||||
nav_set_selected('Language');
|
||||
return lang_selector();
|
||||
return $this->lang_selector();
|
||||
|
||||
}
|
||||
|
||||
private function lang_selector(): string
|
||||
{
|
||||
$lang_options = language_list();
|
||||
array_unshift($lang_options, t('default'));
|
||||
|
||||
$tpl = get_markup_template('lang_selector.tpl');
|
||||
|
||||
return replace_macros($tpl, [
|
||||
'$title' => t('Select an alternate language'),
|
||||
'$langs' => array($lang_options, App::$language),
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ class Like extends Controller {
|
||||
'like' => 'Like',
|
||||
'dislike' => 'Dislike',
|
||||
'announce' => ACTIVITY_SHARE,
|
||||
'attendyes' => 'Accept',
|
||||
'attendno' => 'Reject',
|
||||
'attendmaybe' => 'TentativeAccept'
|
||||
'accept' => 'Accept',
|
||||
'reject' => 'Reject',
|
||||
'tentativeaccept' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
// unlike (etc.) reactions are an undo of positive reactions, rather than a negative action.
|
||||
@@ -52,43 +52,31 @@ class Like extends Controller {
|
||||
profile_load($parts[0]);
|
||||
}
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
if ($page_mode === 'list') {
|
||||
$item_normal = item_normal();
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id FROM item
|
||||
WHERE uid = %d $item_normal
|
||||
AND parent = %d",
|
||||
intval($arr['item']['uid']),
|
||||
intval($arr['item']['parent'])
|
||||
);
|
||||
|
||||
xchan_query($items, true);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$items = conv_sort($items, 'commented');
|
||||
}
|
||||
else {
|
||||
$activities = q("SELECT item.*, item.id AS item_id FROM item
|
||||
WHERE uid = %d $item_normal
|
||||
AND thr_parent = '%s'
|
||||
AND verb IN ('%s', '%s', '%s', '%s', '%s', '%s', 'Accept', 'Reject', 'TentativeAccept')",
|
||||
intval($arr['item']['uid']),
|
||||
dbesc($arr['item']['mid']),
|
||||
dbesc('Like'),
|
||||
dbesc('Dislike'),
|
||||
dbesc(ACTIVITY_SHARE),
|
||||
dbesc(ACTIVITY_ATTEND),
|
||||
dbesc(ACTIVITY_ATTENDNO),
|
||||
dbesc(ACTIVITY_ATTENDMAYBE)
|
||||
);
|
||||
xchan_query($activities, true);
|
||||
$items = array_merge([$arr['item']], $activities);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$item = item_by_item_id($arr['item']['id'], $arr['item']['parent'], 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,12 +5,28 @@ namespace Zotlabs\Module;
|
||||
class Login extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
if(local_channel())
|
||||
goaway(z_root());
|
||||
if(remote_channel() && $_SESSION['atoken'])
|
||||
if (local_channel()) {
|
||||
goaway(z_root());
|
||||
}
|
||||
|
||||
return login(true);
|
||||
if (remote_channel() && $_SESSION['atoken']) {
|
||||
goaway(z_root());
|
||||
}
|
||||
|
||||
if (!empty($_GET['retry'])) {
|
||||
notice( t('Login failed.') . EOL );
|
||||
}
|
||||
|
||||
$o = '<div class="generic-content-wrapper">';
|
||||
$o .= '<div class="section-title-wrapper">';
|
||||
$o .= '<h2 class="">' . t('Login') . '</h2>';
|
||||
$o .= '</div>';
|
||||
$o .= '<div class="section-content-wrapper">';
|
||||
$o .= login(true);
|
||||
$o .= '</div>';
|
||||
$o .= '</div>';
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,11 +41,7 @@ class Magic extends Controller {
|
||||
http_status_exit(400, 'Bad Request');
|
||||
}
|
||||
|
||||
$basepath = unparse_url(array_filter(
|
||||
$parsed,
|
||||
fn (string $key) => in_array($key, ['scheme', 'host', 'port']),
|
||||
ARRAY_FILTER_USE_KEY
|
||||
));
|
||||
$basepath = unparse_url($parsed, ['scheme', 'host', 'port']);
|
||||
|
||||
$owapath = SConfig::get($basepath, 'system', 'openwebauth', $basepath . '/owa');
|
||||
|
||||
@@ -134,11 +130,22 @@ class Magic extends Controller {
|
||||
$args = (($x) ? '&owt=' . $token : '?owt=' . $token) . (($delegate) ? '&delegate=1' : '');
|
||||
goaway($dest . $args);
|
||||
}
|
||||
else {
|
||||
$o = '<h1>OWA ERROR</h1>';
|
||||
if (!empty($j['message'])) {
|
||||
$o .= '<h2>' . $j['message'] . '</h2>';
|
||||
}
|
||||
$o .= '<a href=' . $dest . '>' . $dest . '</a>';
|
||||
|
||||
echo $o;
|
||||
killme();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
killme();
|
||||
goaway($dest);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class Moderate extends \Zotlabs\Web\Controller {
|
||||
|
||||
$item['item_blocked'] = 0;
|
||||
item_update_parent_commented($item);
|
||||
notice( t('Item approved') . EOL);
|
||||
info(t('Item approved') . EOL);
|
||||
}
|
||||
elseif($action === 'drop') {
|
||||
// TODO: not implemented
|
||||
@@ -75,7 +75,7 @@ class Moderate extends \Zotlabs\Web\Controller {
|
||||
// Activity::send_rejection_activity(App::get_channel(), $item['author_xchan'], $item);
|
||||
|
||||
drop_item($post_id);
|
||||
notice( t('Item deleted') . EOL);
|
||||
info(t('Item deleted') . EOL);
|
||||
}
|
||||
|
||||
// refetch the item after changes have been made
|
||||
|
||||
@@ -70,17 +70,19 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
$dm = ((x($_REQUEST,'dm')) ? $_REQUEST['dm'] : 0);
|
||||
|
||||
|
||||
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
|
||||
$order = get_pconfig(local_channel(), 'mod_network', 'order', 'created');
|
||||
switch($order) {
|
||||
case 0:
|
||||
$order = 'comment';
|
||||
case 'commented':
|
||||
$ordering = 'commented';
|
||||
break;
|
||||
case 1:
|
||||
$order = 'post';
|
||||
case 'created':
|
||||
$ordering = 'created';
|
||||
break;
|
||||
case 2:
|
||||
case 'unthreaded':
|
||||
$nouveau = true;
|
||||
break;
|
||||
default:
|
||||
$ordering = 'created';
|
||||
}
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
@@ -92,7 +94,7 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($datequery)
|
||||
$order = 'post';
|
||||
$order = 'created';
|
||||
|
||||
|
||||
// filter by collection (e.g. group)
|
||||
@@ -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'] ?? '';
|
||||
|
||||
@@ -18,96 +18,97 @@ use Zotlabs\Web\Controller;
|
||||
|
||||
class Owa extends Controller {
|
||||
|
||||
function init() {
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
$ret = [ 'success' => false ];
|
||||
|
||||
if (array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) {
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER'];
|
||||
if (!$this->validateAuthorizationHeader()) {
|
||||
$this->error('Missing or invalid authorization header.');
|
||||
}
|
||||
|
||||
if (array_key_exists('HTTP_AUTHORIZATION',$_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') {
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
|
||||
if ($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
$parsed = parse_url($keyId);
|
||||
if (str_starts_with($parsed['scheme'],'http')) {
|
||||
unset($parsed['fragment']);
|
||||
unset($parsed['query']);
|
||||
$keyId = unparse_url($parsed);
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_REMOTE_USER'];
|
||||
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
|
||||
if ($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
$parsed = parse_url($keyId);
|
||||
if (str_starts_with($parsed['scheme'],'http')) {
|
||||
unset($parsed['fragment']);
|
||||
unset($parsed['query']);
|
||||
$keyId = unparse_url($parsed);
|
||||
}
|
||||
else {
|
||||
$keyId = str_replace('acct:', '', $keyId);
|
||||
}
|
||||
if ($keyId) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
|
||||
AND hubloc_deleted = 0 AND xchan_pubkey != ''
|
||||
ORDER BY hubloc_id DESC",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
if (! $r) {
|
||||
$found = discover_by_webbie($keyId);
|
||||
logger('found = ' . print_r($found, true));
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$keyId = str_replace('acct:', '', $keyId);
|
||||
}
|
||||
if ($keyId) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
|
||||
AND hubloc_deleted = 0 AND xchan_pubkey != ''
|
||||
ORDER BY hubloc_id DESC",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
if (! $r) {
|
||||
$found = discover_by_webbie($keyId);
|
||||
logger('found = ' . print_r($found, true));
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
|
||||
dbesc($keyId),
|
||||
dbesc($keyId),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $hubloc) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
||||
logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
break;
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $hubloc) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
||||
logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
break;
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
if (!$ret['success']) {
|
||||
|
||||
if (!$ret['success']) {
|
||||
// Possible a reinstall?
|
||||
// In this case we probably already have an old hubloc
|
||||
// but not the new one yet.
|
||||
|
||||
// Possible a reinstall?
|
||||
// In this case we probably already have an old hubloc
|
||||
// but not the new one yet.
|
||||
$found = discover_by_webbie($keyId);
|
||||
|
||||
$found = discover_by_webbie($keyId);
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
|
||||
dbesc(str_replace('acct:', '', $keyId)),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($found) {
|
||||
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
|
||||
dbesc(str_replace('acct:', '', $keyId)),
|
||||
dbesc($keyId)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
|
||||
logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
if ($r) {
|
||||
$verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
|
||||
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
|
||||
logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
|
||||
logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
} else {
|
||||
logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,4 +119,33 @@ class Owa extends Controller {
|
||||
|
||||
json_return_and_die($ret,'application/x-zot+json');
|
||||
}
|
||||
|
||||
private function validateAuthorizationHeader(): bool
|
||||
{
|
||||
if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
$auth = trim($_SERVER['HTTP_AUTHORIZATION']);
|
||||
} else if (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
|
||||
$auth = trim($_SERVER['REDIRECT_REMOTE_USER']);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strncmp($auth, 'Signature', 9) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the request, and return a json error response.
|
||||
*
|
||||
* @Note This function does not return!
|
||||
*
|
||||
* @param string $msg The error message for the response.
|
||||
*/
|
||||
private function error(string $msg): void {
|
||||
$ret = [
|
||||
'success' => false,
|
||||
'message' => $msg
|
||||
];
|
||||
|
||||
json_return_and_die($ret,'application/x-zot+json');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +557,9 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
|
||||
$can_post = false;
|
||||
$visitor = 0;
|
||||
|
||||
$link_item = null;
|
||||
$like = null;
|
||||
$dislike = null;
|
||||
|
||||
$owner_uid = \App::$data['channel']['channel_id'];
|
||||
$owner_aid = \App::$data['channel']['channel_account_id'];
|
||||
@@ -965,7 +967,6 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
$map = null;
|
||||
|
||||
if($linked_items) {
|
||||
|
||||
xchan_query($linked_items);
|
||||
$linked_items = fetch_post_tags($linked_items,true);
|
||||
|
||||
@@ -1103,20 +1104,8 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
$alike = array();
|
||||
$dlike = array();
|
||||
|
||||
$like = '';
|
||||
$dislike = '';
|
||||
|
||||
$conv_responses = array(
|
||||
'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')),
|
||||
'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title'))
|
||||
);
|
||||
|
||||
if($r) {
|
||||
|
||||
foreach($r as $item) {
|
||||
builtin_activity_puller($item, $conv_responses);
|
||||
}
|
||||
|
||||
$like_count = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid']] : '');
|
||||
$like_list = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : '');
|
||||
|
||||
@@ -1217,12 +1206,17 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
$like_e = $like;
|
||||
$dislike_e = $dislike;
|
||||
$paginate = paginate();
|
||||
$responses = [];
|
||||
|
||||
$response_verbs = array('like');
|
||||
if(feature_enabled($owner_uid,'dislike'))
|
||||
$response_verbs[] = 'dislike';
|
||||
if ($link_item) {
|
||||
$response_verbs = ['like'];
|
||||
|
||||
$responses = get_responses($conv_responses,$response_verbs,'',$link_item);
|
||||
if(feature_enabled($owner_uid,'dislike')) {
|
||||
$response_verbs[] = 'dislike';
|
||||
}
|
||||
|
||||
$responses = get_responses($response_verbs, $link_item);
|
||||
}
|
||||
|
||||
$hookdata = [
|
||||
'onclick' => '$.colorbox({href: \'' . $photo['href'] . '\'}); return false;',
|
||||
|
||||
@@ -29,8 +29,9 @@ class Pin extends \Zotlabs\Web\Controller {
|
||||
if(! $observer)
|
||||
http_status_exit(403, 'Forbidden');
|
||||
|
||||
$r = q("SELECT * FROM item WHERE id = %d AND id = parent AND item_private = 0 LIMIT 1",
|
||||
$item_id
|
||||
$r = q("SELECT * FROM item WHERE id = %d AND uid = %d AND id = parent AND item_private = 0 LIMIT 1",
|
||||
intval($item_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
if(! $r) {
|
||||
notice(t('Unable to locate original post.'));
|
||||
|
||||
@@ -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 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 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 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 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",
|
||||
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,19 +9,29 @@ class Zot_probe extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
if (!local_channel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$addr = $_GET['addr'] ?? '';
|
||||
|
||||
$o = '<h3>Zot6 Probe Diagnostic</h3>';
|
||||
|
||||
$o .= '<form action="zot_probe" method="get">';
|
||||
$o .= 'Lookup URI: <input type="text" style="width: 250px;" name="addr" value="' . $addr .'" /><br>';
|
||||
$o .= '<input type="checkbox" name="sign" /> Sign request <br>';
|
||||
$o .= '<input type="submit" name="submit" value="Submit" /></form>';
|
||||
|
||||
$o .= '<br /><br />';
|
||||
|
||||
if($addr) {
|
||||
|
||||
$x = Zotfinger::exec($addr);
|
||||
$channel = null;
|
||||
if ($_GET['sign']) {
|
||||
$channel = get_sys_channel();
|
||||
}
|
||||
|
||||
$x = Zotfinger::exec($addr, $channel);
|
||||
|
||||
$o .= '<pre>' . htmlspecialchars(print_array($x)) . '</pre>';
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Render;
|
||||
|
||||
use Smarty;
|
||||
use Smarty\Smarty;
|
||||
use App;
|
||||
|
||||
class SmartyInterface extends Smarty {
|
||||
@@ -19,20 +19,20 @@ class SmartyInterface extends Smarty {
|
||||
// The order is thus very important here
|
||||
|
||||
$template_dirs = array('theme' => "view/theme/$thname/tpl/");
|
||||
if ( x(App::$theme_info,"extends") ) {
|
||||
if (!empty(App::$theme_info['extends'])) {
|
||||
$template_dirs = $template_dirs + array('extends' => "view/theme/" . App::$theme_info["extends"] . "/tpl/");
|
||||
}
|
||||
$template_dirs = $template_dirs + array('base' => 'view/tpl/');
|
||||
$this->setTemplateDir($template_dirs);
|
||||
|
||||
$basecompiledir = App::$config['system']['smarty3_folder'];
|
||||
|
||||
|
||||
$this->setCompileDir($basecompiledir.'/compiled/');
|
||||
$this->setConfigDir($basecompiledir.'/config/');
|
||||
$this->setCacheDir($basecompiledir.'/cache/');
|
||||
|
||||
$this->left_delimiter = App::get_template_ldelim('smarty3');
|
||||
$this->right_delimiter = App::get_template_rdelim('smarty3');
|
||||
$this->setLeftDelimiter(App::get_template_ldelim('smarty3'));
|
||||
$this->setRightDelimiter(App::get_template_rdelim('smarty3'));
|
||||
|
||||
// Don't report errors so verbosely
|
||||
$this->error_reporting = E_ALL & ~E_WARNING & ~E_NOTICE;
|
||||
|
||||
@@ -26,9 +26,9 @@ class Theme {
|
||||
*/
|
||||
static public function current() {
|
||||
|
||||
self::$system_theme = ((isset(App::$config['system']['theme']))
|
||||
self::$system_theme = ((!empty(App::$config['system']['theme']))
|
||||
? App::$config['system']['theme'] : '');
|
||||
self::$session_theme = ((isset($_SESSION) && x($_SESSION, 'theme'))
|
||||
self::$session_theme = ((!empty($_SESSION['theme']))
|
||||
? $_SESSION['theme'] : self::$system_theme);
|
||||
|
||||
$page_theme = null;
|
||||
@@ -87,8 +87,13 @@ class Theme {
|
||||
// Find any theme at all and use it.
|
||||
|
||||
$fallback = array_merge(glob('view/theme/*/css/style.css'), glob('view/theme/*/php/style.php'));
|
||||
if(count($fallback))
|
||||
return(array(str_replace('view/theme/', '', substr($fallback[0], 0, -14))));
|
||||
|
||||
if (empty($fallback)) {
|
||||
logger('Unable to find a theme');
|
||||
http_status_exit(500, 'internal server error');
|
||||
}
|
||||
|
||||
return(array(str_replace('view/theme/', '', substr($fallback[0], 0, -14))));
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +116,7 @@ class Theme {
|
||||
$opts = '';
|
||||
$opts = (($uid) ? '?puid=' . $uid : '');
|
||||
|
||||
$schema_str = ((x(App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
|
||||
$schema_str = ((!empty(App::$layout['schema'])) ? '&schema=' . App::$layout['schema'] : '');
|
||||
if(($s) && (! $schema_str))
|
||||
$schema_str = '&schema=' . $s;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Zotlabs\Storage;
|
||||
use Sabre\DAV;
|
||||
use App;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Text;
|
||||
|
||||
/**
|
||||
* @brief Provides a DAV frontend for the webbrowser.
|
||||
@@ -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);
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
namespace Zotlabs\Thumbs;
|
||||
|
||||
use SebLucas\EPubMeta\EPub;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use DOMXPath;
|
||||
use GdImage;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
* Thumbnail creation for epub files.
|
||||
@@ -24,20 +27,21 @@ class Epubthumb {
|
||||
* Create the thumbnail if the Epub has a cover.
|
||||
*
|
||||
* @param array $attach
|
||||
* @param number $preview_style unused
|
||||
* @param number $height (optional) default 300
|
||||
* @param number $width (optional) default 300
|
||||
* @param int $preview_style unused
|
||||
* @param int $height (optional) default 300
|
||||
* @param int $width (optional) default 300
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
*/
|
||||
function Thumb($attach, $preview_style, $height = 300, $width = 300) {
|
||||
function Thumb($attach, $preview_style, $height = 300, $width = 300): void {
|
||||
|
||||
$file = dbunescbin($attach['content']);
|
||||
if (!$file) {
|
||||
return;
|
||||
}
|
||||
|
||||
$image = $this->getCover($file);
|
||||
$image = $this->getCoverFromEpub($file);
|
||||
|
||||
if ($image) {
|
||||
$srcwidth = imagesx($image);
|
||||
@@ -56,15 +60,139 @@ class Epubthumb {
|
||||
}
|
||||
}
|
||||
|
||||
private function getCover(string $filename): GdImage|false {
|
||||
$epub = new EPub($filename);
|
||||
$cover = $epub->getCover();
|
||||
/**
|
||||
* Fetch the cover from the epub archive, if it's present.
|
||||
*
|
||||
* There's a few limitations here: This will only work if the cover
|
||||
* is a raster image of a supported format. SVG does not work, neither
|
||||
* will other schemes sometimes used for cover/front page.
|
||||
*
|
||||
* @param string $filename The local filename of the epub archive.
|
||||
*
|
||||
* @return GdImage|false If a cover is found, it is returned as a
|
||||
* GdImage object. Otherwise return false.
|
||||
*/
|
||||
private function getCoverFromEpub(string $filename): GdImage|false {
|
||||
$epub = new ZipArchive();
|
||||
$rc = $epub->open($filename, ZipArchive::RDONLY);
|
||||
|
||||
if (! empty($cover)) {
|
||||
if ($rc !== true) {
|
||||
logger("Error opening file '{$filename}': rc = ${rc}.", LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cover = false;
|
||||
$cover_name = $this->parseEpub($epub);
|
||||
if ($cover_name !== false) {
|
||||
$cover = $epub->getFromName($cover_name);
|
||||
if ($cover === false) {
|
||||
logger("File '{$cover_name}' not found in EPUB.", LOGGER_DEBUG, LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
$epub->close();
|
||||
|
||||
if ($cover !== false && !empty($cover)) {
|
||||
return imagecreatefromstring($cover);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the epub to find the path of the cover image.
|
||||
*
|
||||
* @param ZipArchive $epub An opened epub ZipArchive.
|
||||
*
|
||||
* @return string|false The path to the cover image or false.
|
||||
*/
|
||||
private function parseEpub(ZipArchive $epub): string|false {
|
||||
$packagePath = $this->getEpubPackagePath($epub);
|
||||
if ($packagePath !== false) {
|
||||
$package = $epub->getFromName($packagePath);
|
||||
if ($package === false || empty($package)) {
|
||||
logger("Package file '${packagePath}' not found in EPUB", LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$domdoc = new DOMDocument();
|
||||
$domdoc->loadXML($package);
|
||||
$xpath = new DOMXPath($domdoc);
|
||||
$xpath->registerNamespace("n", "http://www.idpf.org/2007/opf");
|
||||
$nodes = $xpath->query('/n:package/n:manifest/n:item[@properties="cover-image"]');
|
||||
|
||||
if ($nodes->count() === 0) {
|
||||
logger('No cover found in EPUB manifest.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$node = $nodes->item(0);
|
||||
if ($node === null) {
|
||||
logger('No nodes in non-empty node list?', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_a($node, DOMElement::class)) {
|
||||
// The URL's in the package file is relative to the subdirectory
|
||||
// within the epub archive where it is located. See
|
||||
// https://www.w3.org/TR/epub-33/#sec-parsing-urls-metainf
|
||||
return dirname($packagePath) . '/' . $node->getAttribute('href');
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the package file within the epub.
|
||||
*
|
||||
* The package file in an epub archive contains the manifest
|
||||
* that again may contain a reference to the cover for the
|
||||
* epub.
|
||||
*
|
||||
* @param ZipArchive $epub An opened epub archive.
|
||||
*
|
||||
* @return string|false The full pathname of the package file or false.
|
||||
*/
|
||||
private function getEpubPackagePath(ZipArchive $epub): string|false {
|
||||
//
|
||||
// The only mandatory known file within the archive is the
|
||||
// container file, so we fetch it to find the reference to
|
||||
// the package file.
|
||||
//
|
||||
// See: https://www.w3.org/TR/epub-33/#sec-container-metainf
|
||||
//
|
||||
$container = $epub->getFromName('META-INF/container.xml');
|
||||
|
||||
if ($container === false || empty($container)) {
|
||||
logger('No container in archive, probably not an EPUB.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$domdoc = new DOMDocument();
|
||||
$domdoc->loadXML($container);
|
||||
$nodes = $domdoc->getElementsByTagName('rootfile');
|
||||
|
||||
if ($nodes->count() == 0) {
|
||||
logger('EPUB rootfile not found, is this an epub?', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$packageNode = $nodes->item(0);
|
||||
if ($packageNode === null || !is_a($packageNode, DOMElement::class)) {
|
||||
logger('EPUB rootfile element missing or invalid.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$packagePath = $packageNode->getAttribute('full-path');
|
||||
$packageMediaType = $packageNode->getAttribute('media-type');
|
||||
|
||||
if (empty($packagePath) || $packageMediaType !== 'application/oebps-package+xml') {
|
||||
logger('EPUB package path missing or incorrect media type.', LOGGER_DEBUG, LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $packagePath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user