mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 09:01:15 -04:00
Compare commits
1048 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deb4c54ebf | ||
|
|
281f518705 | ||
|
|
a8d9747b12 | ||
|
|
4b15b07b8b | ||
|
|
607a5488d6 | ||
|
|
519b52ccdc | ||
|
|
99fd2e1cb9 | ||
|
|
a69c460ee6 | ||
|
|
71ba6406e3 | ||
|
|
4922acb18a | ||
|
|
a0ea19e51c | ||
|
|
8c4457db8b | ||
|
|
89a1af1794 | ||
|
|
d5e0c24e13 | ||
|
|
8fe73d73ce | ||
|
|
7559d6bb5c | ||
|
|
6c40576f94 | ||
|
|
1c9c0dc70e | ||
|
|
bf4227bfef | ||
|
|
c296d4bbed | ||
|
|
68452fb07b | ||
|
|
7f98cd606b | ||
|
|
d0ae7a0493 | ||
|
|
81e79eec04 | ||
|
|
7d70f2f0f2 | ||
|
|
016a11ad27 | ||
|
|
1637e61681 | ||
|
|
1ec0e91405 | ||
|
|
3ab52a060b | ||
|
|
866cd52073 | ||
|
|
1774140307 | ||
|
|
698dce044d | ||
|
|
bf0d73515e | ||
|
|
8152da1275 | ||
|
|
01de48b994 | ||
|
|
eb10820195 | ||
|
|
9d33456c89 | ||
|
|
56c7f76230 | ||
|
|
3dd9559d9f | ||
|
|
51ac502d97 | ||
|
|
955ee217e3 | ||
|
|
6d8bfe58ef | ||
|
|
f98f540256 | ||
|
|
54c7319075 | ||
|
|
72c930f964 | ||
|
|
ce24b86841 | ||
|
|
f63ba541d7 | ||
|
|
a9f54473db | ||
|
|
eb5ea6536b | ||
|
|
2e9b64347d | ||
|
|
4fcff43fb5 | ||
|
|
260b61ba3b | ||
|
|
d0b7e4ea79 | ||
|
|
33c95c810a | ||
|
|
81105ff9de | ||
|
|
ced3113516 | ||
|
|
cbd208eea3 | ||
|
|
ad85825cab | ||
|
|
2fb816139a | ||
|
|
c9166b26c5 | ||
|
|
86d58065b3 | ||
|
|
1f265cc6d5 | ||
|
|
4474fdd4f9 | ||
|
|
f71eeab5be | ||
|
|
b3526415f9 | ||
|
|
471ded3efa | ||
|
|
e954d8c55e | ||
|
|
70f82c3967 | ||
|
|
707e07bbbc | ||
|
|
e89eb04427 | ||
|
|
ae0e82ee3a | ||
|
|
9ea5d20a3d | ||
|
|
fd69008484 | ||
|
|
3256aa8be9 | ||
|
|
add26a5b5f | ||
|
|
dc03263bef | ||
|
|
1897cd0b1b | ||
|
|
ba24958b37 | ||
|
|
52a2a0d89a | ||
|
|
91944da69e | ||
|
|
78e30a4d32 | ||
|
|
ccd6d1a38c | ||
|
|
f14c1be963 | ||
|
|
db5e92b72d | ||
|
|
3d3580b23f | ||
|
|
04d44c9965 | ||
|
|
82bd91d9d7 | ||
|
|
492533729d | ||
|
|
283b606c09 | ||
|
|
b0b5523f2b | ||
|
|
738797467d | ||
|
|
a2ee5705f4 | ||
|
|
cc1713b69a | ||
|
|
6f5e4c5c2e | ||
|
|
3e0b9c01b6 | ||
|
|
25218fea43 | ||
|
|
c907e569f1 | ||
|
|
b6bec6f7b7 | ||
|
|
31b5cfe7ef | ||
|
|
0efb3c5c95 | ||
|
|
d88f3169c8 | ||
|
|
3772e910df | ||
|
|
e995d45b53 | ||
|
|
669136bce7 | ||
|
|
2448e6df27 | ||
|
|
4c0b37db66 | ||
|
|
85d42cebe2 | ||
|
|
fcafaef190 | ||
|
|
6fa8deddb5 | ||
|
|
0ea3f3d36d | ||
|
|
1ef7fcda0a | ||
|
|
cb7dc2059a | ||
|
|
e988bc9fae | ||
|
|
bbd60c1a31 | ||
|
|
951187e540 | ||
|
|
cb23a9e235 | ||
|
|
8d9623674d | ||
|
|
0c835c3403 | ||
|
|
6d181ee69e | ||
|
|
0b491a6626 | ||
|
|
1a0684cc55 | ||
|
|
2d97f8fa25 | ||
|
|
98a3c97820 | ||
|
|
081a61a276 | ||
|
|
89e1328ed0 | ||
|
|
3b516f2ded | ||
|
|
8c386191fa | ||
|
|
5cb4db0353 | ||
|
|
dc43cd9a85 | ||
|
|
5a6a7386a8 | ||
|
|
4f545e31dd | ||
|
|
437c0a8913 | ||
|
|
268fccdb30 | ||
|
|
bb7689be93 | ||
|
|
bd63af69b2 | ||
|
|
e5d4358d61 | ||
|
|
0fa4962620 | ||
|
|
fe4d6229a4 | ||
|
|
10c5de4f6e | ||
|
|
99a1569d07 | ||
|
|
9fb5cd12be | ||
|
|
d85c737db7 | ||
|
|
9657fc50e9 | ||
|
|
de468a29b0 | ||
|
|
794b456b8a | ||
|
|
a0cb5fcb3f | ||
|
|
0d382634ec | ||
|
|
225c83dfbe | ||
|
|
083c4c95d1 | ||
|
|
e736945f1d | ||
|
|
4a2e5add36 | ||
|
|
067a79a778 | ||
|
|
cb0102b971 | ||
|
|
8b46767d30 | ||
|
|
26b5dabe72 | ||
|
|
3f39d0d249 | ||
|
|
2b4d2baa7b | ||
|
|
3130a94a4c | ||
|
|
d44c004bd0 | ||
|
|
c655046e1f | ||
|
|
b32c1c1e22 | ||
|
|
38f040f9b5 | ||
|
|
7dcaebf281 | ||
|
|
fad5f98405 | ||
|
|
ea07bd1693 | ||
|
|
4a7b2e92a5 | ||
|
|
deaab14c5f | ||
|
|
8258b8b088 | ||
|
|
db5c217a21 | ||
|
|
724ee7dbab | ||
|
|
fb9fe0d3c4 | ||
|
|
9019636449 | ||
|
|
933b4fbcfe | ||
|
|
7675ed0145 | ||
|
|
73e7f0aad2 | ||
|
|
f25211d7ff | ||
|
|
30cf6d827c | ||
|
|
1323ea8e18 | ||
|
|
9f98f6bbd5 | ||
|
|
cedc6c4230 | ||
|
|
b6a58fbf6e | ||
|
|
e295765bef | ||
|
|
141dc2fdb7 | ||
|
|
c051c4d0aa | ||
|
|
e289078f82 | ||
|
|
87f79381d9 | ||
|
|
98840ae1d0 | ||
|
|
28746891c8 | ||
|
|
e5d0ef79ef | ||
|
|
2eb51233f6 | ||
|
|
5432819788 | ||
|
|
c03f543b54 | ||
|
|
de6506eb57 | ||
|
|
fb48bbe2c1 | ||
|
|
65132c8fdc | ||
|
|
2c0936187a | ||
|
|
48dbba2f4d | ||
|
|
16068af0bb | ||
|
|
d09b01245f | ||
|
|
bdd0b0a6fb | ||
|
|
48030617ab | ||
|
|
bb49a51be3 | ||
|
|
da266f5739 | ||
|
|
f6a4997d6f | ||
|
|
7a99089204 | ||
|
|
2e55973da2 | ||
|
|
80f4eea9e9 | ||
|
|
be5c8aa2a3 | ||
|
|
643d25b34b | ||
|
|
c29d79854e | ||
|
|
2834544451 | ||
|
|
60eb8aa42b | ||
|
|
aff39521cd | ||
|
|
f19ad4b087 | ||
|
|
fc243196d9 | ||
|
|
42e78d9666 | ||
|
|
26d1653bfb | ||
|
|
f39ccab6c1 | ||
|
|
a0e6dcbb77 | ||
|
|
320a0c1b62 | ||
|
|
84d52a9ad1 | ||
|
|
dc298ce6c1 | ||
|
|
b464cd6181 | ||
|
|
4eb7e29bab | ||
|
|
63243808b8 | ||
|
|
f271448767 | ||
|
|
3915164bb4 | ||
|
|
94e5aa172c | ||
|
|
ff68bee174 | ||
|
|
25aa7d5738 | ||
|
|
07e3a218cb | ||
|
|
e6ad00dabc | ||
|
|
23d781e348 | ||
|
|
b53cacd54c | ||
|
|
ade3da4d89 | ||
|
|
1e5f614a5e | ||
|
|
159c8dbd5f | ||
|
|
5faa285f6f | ||
|
|
c9af19cdb2 | ||
|
|
3e74e4784c | ||
|
|
bcbd7f4f6d | ||
|
|
7ead6086dc | ||
|
|
4685568e0d | ||
|
|
ec57f8293a | ||
|
|
9e5344d624 | ||
|
|
4c122fd3b3 | ||
|
|
d318a1b807 | ||
|
|
7959dd9f57 | ||
|
|
fde03c7ae0 | ||
|
|
7fcc770fbf | ||
|
|
dcb09a8b39 | ||
|
|
57c22f4d0f | ||
|
|
ed1cfa5c7b | ||
|
|
3878dbd6bd | ||
|
|
e80de634d3 | ||
|
|
536f80e50b | ||
|
|
554577fad7 | ||
|
|
3eeb173efd | ||
|
|
3ac99479fe | ||
|
|
7cadb43029 | ||
|
|
f25ac63f18 | ||
|
|
8a79d8d06f | ||
|
|
ddf7fad82f | ||
|
|
6a9d569d5a | ||
|
|
ad017baaa6 | ||
|
|
b5d673c102 | ||
|
|
d7fa707f00 | ||
|
|
b4b7ec1693 | ||
|
|
6f8b7f177d | ||
|
|
7a2a621309 | ||
|
|
fe25bab3a7 | ||
|
|
3abd764512 | ||
|
|
dc255a4ecf | ||
|
|
fc201ae067 | ||
|
|
de5455b401 | ||
|
|
1243207b8f | ||
|
|
39f4a56348 | ||
|
|
d48c9ce562 | ||
|
|
6ced694b53 | ||
|
|
bc128c604b | ||
|
|
a2168870b9 | ||
|
|
c0197b698e | ||
|
|
f2ae99f64e | ||
|
|
14f6667687 | ||
|
|
6f9348540e | ||
|
|
51b667020e | ||
|
|
c6d54d03de | ||
|
|
8e35ef2faa | ||
|
|
b74a2dff9e | ||
|
|
6400bcc81f | ||
|
|
4abe0703d7 | ||
|
|
4b389ddba9 | ||
|
|
1e92aeb7f9 | ||
|
|
b6153edf6b | ||
|
|
93c333a9bc | ||
|
|
43142dde9f | ||
|
|
63bc905061 | ||
|
|
573c6f3df3 | ||
|
|
28692b867c | ||
|
|
74b8f1f240 | ||
|
|
0be74299ca | ||
|
|
e90fc6d714 | ||
|
|
866d88de53 | ||
|
|
69acee497d | ||
|
|
6c74672d40 | ||
|
|
6320506c27 | ||
|
|
1ee0f3ce1d | ||
|
|
0730d31c22 | ||
|
|
a2a8b2e9fb | ||
|
|
8821fa9a0e | ||
|
|
363100a612 | ||
|
|
1f7ac5e787 | ||
|
|
2233a0317e | ||
|
|
498ef78e6f | ||
|
|
8a606365c8 | ||
|
|
9c27f94709 | ||
|
|
a99e067b91 | ||
|
|
831f4324ae | ||
|
|
ad205abd90 | ||
|
|
231f4a28eb | ||
|
|
95b52b6aa9 | ||
|
|
385c23a2b6 | ||
|
|
3a81edbcb0 | ||
|
|
2f377089e6 | ||
|
|
6427e84053 | ||
|
|
f1def0c03a | ||
|
|
b8a5ebe0f7 | ||
|
|
24a9ad6260 | ||
|
|
88577e1e97 | ||
|
|
38225aabc9 | ||
|
|
3653ae1af0 | ||
|
|
f2aa42f18a | ||
|
|
aa5bd9bbfc | ||
|
|
73b931ed14 | ||
|
|
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 | ||
|
|
c2a09434ca | ||
|
|
6068c0e8c2 | ||
|
|
fd86ccb4eb | ||
|
|
c36d159997 | ||
|
|
efd61cb43a | ||
|
|
b79c19c66d | ||
|
|
ee4cc51a05 | ||
|
|
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 | ||
|
|
30d552255e | ||
|
|
0522bd5593 | ||
|
|
a46d837267 | ||
|
|
bee493f628 | ||
|
|
a4f4a082af | ||
|
|
dd9ab07044 | ||
|
|
afd811a875 | ||
|
|
122d46b79b | ||
|
|
36448adad4 | ||
|
|
8f93d9aa75 | ||
|
|
76f50d7150 | ||
|
|
80c9880a67 | ||
|
|
d1f54507f6 | ||
|
|
334852d733 | ||
|
|
34b2bdcf2c | ||
|
|
5188b9cef5 | ||
|
|
8c0b7ce4de | ||
|
|
17d0d6f75d | ||
|
|
059113d2a8 | ||
|
|
f60dff788e |
@@ -34,14 +34,14 @@ if you look for more choices. The main differences are:
|
||||
Hardware
|
||||
|
||||
+ internet connection and router at home
|
||||
+ computer connected to your router (a Raspberry 3 will do for very small Hubs)
|
||||
+ computer connected to your router (a Raspberry 4 will do for very small Hubs)
|
||||
|
||||
Software
|
||||
|
||||
+ fresh installation of Debian 12 (bookworm)
|
||||
+ fresh installation of Debian 12 (bookworm) or Raspberry Pi OS
|
||||
+ router with open ports 80 and 443 for your web server
|
||||
|
||||
You can of course run the script on a VPS or any distant server as long as the above sotfware requirements are satisfied.
|
||||
You can of course run the script on a VPS or any distant server as long as the above software requirements are satisfied.
|
||||
|
||||
## How to run the script
|
||||
|
||||
@@ -80,6 +80,11 @@ Switch the verification off
|
||||
|
||||
util/config system verify_email 0
|
||||
|
||||
Check if updates from the repository do work
|
||||
|
||||
util/udall
|
||||
|
||||
|
||||
## What the script will do for you...
|
||||
|
||||
+ install everything required by your hubzilla instance, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||
@@ -99,7 +104,7 @@ The script is known to work without adjustments with
|
||||
|
||||
+ Hardware
|
||||
- standard PC with Debian 12 (bookworm)
|
||||
- Raspberry 4 with Raspbian, Debian 12 (TODO: needs confirmation after swich to Debian12)
|
||||
- Raspberry 5 with Raspberry Pi OS, Debian 12
|
||||
- for tesing purposes: under localhost inside a virtual machine, [KVM](https://wiki.debian.org/KVM)
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
@@ -149,5 +154,3 @@ It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
|
||||
@@ -160,8 +160,8 @@ function install_composer {
|
||||
print_info "We check if Composer is already downloaded"
|
||||
if [ ! -f /usr/local/bin/composer ]
|
||||
then
|
||||
EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
|
||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
EXPECTED_CHECKSUM="`wget -qO- https://composer.github.io/installer.sig`"
|
||||
wget https://getcomposer.org/installer -O composer-setup.php
|
||||
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
||||
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
|
||||
then
|
||||
@@ -171,6 +171,7 @@ function install_composer {
|
||||
fi
|
||||
php composer-setup.php --quiet
|
||||
RESULT=$?
|
||||
composer --version
|
||||
rm composer-setup.php
|
||||
# exit $RESULT
|
||||
# We install Composer globally
|
||||
@@ -181,7 +182,7 @@ function install_composer {
|
||||
fi
|
||||
cd $install_path
|
||||
export COMPOSER_ALLOW_SUPERUSER=1;
|
||||
/usr/local/bin/composer install --no-dev
|
||||
/usr/local/bin/composer install --no-dev --quiet
|
||||
/usr/local/bin/composer show
|
||||
export COMPOSER_ALLOW_SUPERUSER=0;
|
||||
}
|
||||
@@ -307,10 +308,19 @@ function install_run_selfhost {
|
||||
# https://carol.selfhost.de/update?username=123456&password=supersafe
|
||||
#
|
||||
# the prefered way
|
||||
wget --output-document=$selfhostdir/$selfhostscript http://jonaspasche.de/selfhost-updater
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
if [ ! -f $selfhostdir/$selfhostscript ]
|
||||
then
|
||||
wget --output-document=$selfhostdir/$selfhostscript https://jonaspasche.de/selfhost-updater
|
||||
if [ ! -s $selfhostdir/$selfhostscript ]
|
||||
then
|
||||
die "Failed to download selfHOST file for dynDNS"
|
||||
fi
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
print_info "Wrote file to update dynamic IP. File: $selfhostdir/$selfhostscript"
|
||||
fi
|
||||
print_info "executing $selfhostdir/$selfhostscript update..."
|
||||
bash $selfhostdir/$selfhostscript update
|
||||
fi
|
||||
}
|
||||
@@ -386,7 +396,7 @@ function install_letsencrypt {
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||
fi
|
||||
nocheck_install "certbot python-certbot-apache"
|
||||
nocheck_install "certbot python3-certbot-apache"
|
||||
print_info "run certbot ..."
|
||||
certbot --apache -w $install_path -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
|
||||
service apache2 restart
|
||||
@@ -441,7 +451,7 @@ function configure_cron_daily {
|
||||
echo "echo \" \"" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - stopping apache and mysql...\"" >> /var/www/$cron_job
|
||||
echo "service apache2 stop" >> /var/www/$cron_job
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /var/www/$cron_job
|
||||
echo "systemctl stop mysql.service # to avoid inconsistencies" >> /var/www/$cron_job
|
||||
echo "#" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$cron_job
|
||||
echo "certbot renew --noninteractive" >> /var/www/$cron_job
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
stages:
|
||||
- pretest
|
||||
- test
|
||||
- deploy
|
||||
|
||||
@@ -25,23 +26,6 @@ variables:
|
||||
POSTGRES_USER: ci-user
|
||||
POSTGRES_PASSWORD: ci-pass
|
||||
|
||||
|
||||
before_script:
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- apt-get update
|
||||
- apt-get install -yqq libicu-dev libjpeg-dev libpng-dev libpq-dev libyaml-dev libzip-dev mariadb-client postgresql-client unzip zip
|
||||
- pecl install xdebug yaml
|
||||
- docker-php-ext-enable xdebug yaml
|
||||
- docker-php-ext-configure gd --with-jpeg=/usr/include/
|
||||
- docker-php-ext-install gd bcmath intl pdo_mysql pdo_pgsql zip
|
||||
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php ./composer.phar install --no-progress
|
||||
# php.ini settings
|
||||
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
|
||||
|
||||
# hidden job definition with template for MySQL/MariaDB
|
||||
.job_template_mysql: &job_definition_mysql
|
||||
stage: test
|
||||
@@ -53,13 +37,13 @@ before_script:
|
||||
HZ_TEST_DB_DATABASE: $MYSQL_DATABASE
|
||||
script:
|
||||
# Import hubzilla's DB schema
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$MYSQL_DATABASE"
|
||||
# Show databases and relations/tables of hubzilla's database
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$MYSQL_DATABASE"
|
||||
# Run the actual tests
|
||||
- touch dbfail.out
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- vendor/bin/phpunit -d memory_limit=256M --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
|
||||
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
|
||||
|
||||
@@ -84,7 +68,7 @@ before_script:
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
|
||||
# Run the actual tests
|
||||
- touch dbfail.out
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- vendor/bin/phpunit -d memory_limit=256M --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
|
||||
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
|
||||
|
||||
@@ -100,29 +84,55 @@ before_script:
|
||||
paths:
|
||||
- tests/results/
|
||||
|
||||
default:
|
||||
image: php:8.2
|
||||
before_script:
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- apt-get update
|
||||
- apt-get install -yqq libicu-dev libjpeg-dev libpng-dev libpq-dev libyaml-dev libgmp-dev libzip-dev mariadb-client postgresql-client unzip zip
|
||||
- pecl install xdebug yaml
|
||||
- docker-php-ext-enable xdebug yaml
|
||||
- docker-php-ext-configure gd --with-jpeg=/usr/include/
|
||||
- docker-php-ext-install gd gmp intl pdo_mysql pdo_pgsql zip exif
|
||||
|
||||
# PHP8.1 with MySQL 8.0
|
||||
php8.1_mysql8.0.22:
|
||||
image: php:8.1
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php ./composer.phar install --no-progress
|
||||
# php.ini settings
|
||||
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
|
||||
|
||||
check_templates:
|
||||
stage: pretest
|
||||
script:
|
||||
- touch .htconfig.php
|
||||
- php util/precompile_smarty3.php
|
||||
|
||||
phpstan:
|
||||
stage: pretest
|
||||
script:
|
||||
- touch .htconfig.php
|
||||
- vendor/bin/phpstan --memory-limit=512M
|
||||
|
||||
# PHP8.2 with MySQL 8.0
|
||||
php8.2_mysql8.0.22:
|
||||
services:
|
||||
- mysql:8.0
|
||||
<<: *job_definition_mysql
|
||||
<<: *artifacts_template
|
||||
|
||||
# PHP8.1 with MariaDB 10.6
|
||||
php8.1_mariadb10.6:
|
||||
image: php:8.1
|
||||
# PHP8.2 with MariaDB 10.6
|
||||
php8.2_mariadb10.6:
|
||||
services:
|
||||
- name: mariadb:10.6
|
||||
alias: mysql
|
||||
<<: *job_definition_mysql
|
||||
<<: *artifacts_template
|
||||
|
||||
# PHP8.1 with PostgreSQL 12
|
||||
php8.1_postgres12:
|
||||
image: php:8.1
|
||||
# PHP8.2 with PostgreSQL 14
|
||||
php8.2_postgres14:
|
||||
services:
|
||||
- postgres:12-alpine
|
||||
- postgres:14-alpine
|
||||
<<: *job_definition_postgres
|
||||
<<: *artifacts_template
|
||||
|
||||
|
||||
372
CHANGELOG
372
CHANGELOG
@@ -1,3 +1,375 @@
|
||||
Hubzilla 11.2.1 (2026-05-20)
|
||||
- Fix channel creation failing in some situations
|
||||
- Drop payloads with unsafe json-ld keys in LDSignatures::verify() and add tests
|
||||
- Fix App::$profile set for removed channels
|
||||
- Fix MessageFilter breaking when expecting string but array is given
|
||||
- Superblock: fix blocking failed in some setups (sponsored by NLnet NGI0 Commons Fund/Superblock)
|
||||
- Superblock: fix missing import of attribute (sponsored by NLnet NGI0 Commons Fund/Superblock)
|
||||
- Superblock: improved detection of reshares (sponsored by NLnet NGI0 Commons Fund/Superblock)
|
||||
- Cards: fix PHP warning
|
||||
- Gallery: fix PHP warnings and only implement observer related javascript if there actually is an observer
|
||||
- Diaspora: fix missing local namespace for thr_parent
|
||||
|
||||
|
||||
Hubzilla 11.2 (2026-03-26)
|
||||
Features
|
||||
- Introduce parse_webbie() for preparing webbies and URLs for webfinger usage
|
||||
- Allow to override cUrl useragent
|
||||
- New HQ system status widget for admins (sponsored by NLnet NGI0 Commons Fund/Performance Profiling)
|
||||
- Refactor drop_query_params() to deal with array params and add test
|
||||
|
||||
Maintenance
|
||||
- Remove private members from API docs
|
||||
- Remove custom CA certs
|
||||
- Add type annotations in Extend\Route
|
||||
- Set method visibility in Extend\Route
|
||||
- Add API docs and licence info to Extend\Route
|
||||
- Add a short sleep interval to Activity::init_background_fetch() when adding new work items in a loop
|
||||
- Add a short sleep interval to the convo daemon loop to spread the load for large collections
|
||||
- Use PHP matching rules in util/run_xgettext
|
||||
- Store translation templates as .pot instead of .po
|
||||
- Deprecate NULL_DATE constant in favor of DBA::get_null_date()
|
||||
- Composer require guzzlehttp/psr7
|
||||
- Update composer libs
|
||||
- Move HQ channel notifications widget HTML to template
|
||||
- Deprecate tags and attachment in activities
|
||||
- Update the nginx config example to meet the more modern approach
|
||||
|
||||
Bugfixes
|
||||
- Fix route and widget register() not deduplicating entries
|
||||
- Fix issue in route and widget unregister() where we unregistered even if only one of the two arguments did not match
|
||||
- Fix issue in Storage/Directory where we returned a partial path instead of throwing exception if a directory of a path could not be found
|
||||
- Fix possible endless loop in externals daemon
|
||||
- Fix fatal error in italian translation file
|
||||
- Fix mod network not displaying direct messages when filters active - issue #1973
|
||||
- Fix ghost notifications with reshared items - issue #1970
|
||||
- Fix issue with double typed objects in Lib/Activity
|
||||
- Fix events displaying event timezone instead of adjusted to timezone
|
||||
- Fix duplicated terms in activity object
|
||||
- Fix last modified timestamp not updating in attach_store()
|
||||
|
||||
Addons
|
||||
- Wopi: fix headers already set warning when serving the file to the client
|
||||
- Superblock: complete rewrite with extended functionality and added tests for version 3.0 (sponsored by NLnet NGI0 Commons Fund/Superblock)
|
||||
- Diaspora: use Diaspora/2 useragent when fetching hcards to prevent being redirected to some shady bot guard
|
||||
- Add composer config and autoload files for addons
|
||||
- Wopi: return early in construct_page hook and
|
||||
- Wopi: fix wrong hook name in uninstall function
|
||||
|
||||
|
||||
Hubzilla 11.0 (2026-01-30)
|
||||
Features
|
||||
- Rewrite Lib/MessageFilter (ported from forte) and add more tests
|
||||
- Rewrite editor encryption feature to implement libsodium and PBDKF2 for password hashing
|
||||
- Change default feed behaviour to return only toplevels - issue #1953
|
||||
- Add active themes list to siteinfo
|
||||
- Show viewsource link for pubstream items
|
||||
- Implement singleton object cache
|
||||
- Restructure cross protocol message payload
|
||||
- View source will now display the raw object instead of just the object body
|
||||
- Implement OWA2
|
||||
|
||||
Maintenance
|
||||
- Remove capability to update xchan entries via api
|
||||
- Move mod search HTML to template
|
||||
- Move channel activities HTML to template
|
||||
- Update util/run_xgettext.sh to ignore not relevant directories
|
||||
- Update composer libs
|
||||
- Move mod bookmarks HTML to template
|
||||
- Update italian translation
|
||||
- Use finfo class to determine mime type in attach_store()
|
||||
- Bump attach.filetype field length to match photo.mimetype
|
||||
- Move share container HTML to template
|
||||
- Update cloud directory template to provid necessary data for the WOPI addon
|
||||
- Remove appearances of curl_close() - deprected and noop since PHP version 8.0
|
||||
- Remove appearances of GD imagedestroy() - deprected and noop since PHP version 8.0
|
||||
- Improve replies id detection
|
||||
- Remove deprecated ofeed and ochannel modules
|
||||
- Remove support for deprecated AS1 verbs and objects in the network stream filters
|
||||
- Improve detection of allday events
|
||||
- Improve handling of events with no endTime
|
||||
- Provide the event hash and timezone in the event object
|
||||
- Improve test isolation
|
||||
- Add quoteUri field to activities
|
||||
- Update API docs for hooks
|
||||
- Improve share to quote conversion
|
||||
- Rename (un)serialise() -> json_(un)serialize()
|
||||
- CI: Replace use of create_identity in MagicTest
|
||||
- CI: Add test db fixtures for hubloc table
|
||||
- CI: Stub crypto calls from CreateIdentityTest (performance)
|
||||
- CI: Add tests for Profiles module
|
||||
- CI: Add tests for Zotfinger module
|
||||
- Use json serialisation for iconfig
|
||||
- CI: Add test db fixtures for channel table
|
||||
- CI: Reload test fixtures from db
|
||||
- CI: Set logged in channel for delete account test
|
||||
- CI: Use root passwd to set up MySQL test db
|
||||
- Improve dba_pdo::insert function
|
||||
- Update install document
|
||||
- Remove unused sprintf.js
|
||||
- Move twitteroauth lib to addon_common
|
||||
- Move slinky lib to addon_common
|
||||
- Move openid lib to openid addon
|
||||
- Move XRI lib to wppost addon
|
||||
- Move diff lib to wiki addon
|
||||
- Remove unused bootbox lib
|
||||
- Remove unused images
|
||||
- Move language specific folders into its own subfolder in /view
|
||||
- Remove deprecated sjcl lib and references
|
||||
- Deprecate outbound JSalmon signatures
|
||||
|
||||
Bugfixes
|
||||
- Fix reply-to button not diplayed for anonymous visitors allthough permission is granted
|
||||
- Fix wrong icon class in mod cloud
|
||||
- Fix bulk deleting files
|
||||
- Fix cloud root folder shows unknown error
|
||||
- Fix edited timestamp in attach_store() in case of update
|
||||
- Fix grammar in Lib/Enotify::submit()
|
||||
- Fix content-type and length header in Module\TestCase
|
||||
- Fix args in xchan_fetch() not escaped
|
||||
- Fix notification for events linking to wrong message id - issue #1954
|
||||
- Fix post_mail permission not working independend from the send_stream/post_comment permissions - issue #1951
|
||||
- Fix item relayed again in case it comes back from a channel that sources our channel
|
||||
- Fix activity signer not set
|
||||
- Fix category link not update at clone - issue #1932
|
||||
- Fix tag delivery attempted item type is not post - fix issue #1941
|
||||
- Fix block/unblock account - issue #1947
|
||||
- Fix warnings in profile_edit template
|
||||
- Fix warnings for optional args in field templates
|
||||
- Fix undefined vars in mod profiles
|
||||
- Fix fullscreen button class
|
||||
- Fix delivery report when syncing cloned channels
|
||||
|
||||
Addon
|
||||
- New addon implementing basic WOPI protocol - integrates collabora with the Files app
|
||||
- Redphotos: addon removed - was used for migration from redmatrix to hubzilla
|
||||
- Redfiles: addon removed - was used for migration from redmatrix to hubzilla
|
||||
- Nsfw: rewrite to implement new MessageFilter
|
||||
- Wiki: fix long loading time due to oembed attempts
|
||||
- Wiki: improved SQL query
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ class PermissionRoles {
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['limits']['post_comments'] = PERMS_AUTHED;
|
||||
$ret['limits']['post_mail'] = PERMS_AUTHED;
|
||||
$ret['limits']['post_like'] = PERMS_AUTHED;
|
||||
$ret['limits']['chat'] = PERMS_AUTHED;
|
||||
break;
|
||||
|
||||
@@ -212,6 +212,7 @@ class Permissions {
|
||||
* @return array Associative array with
|
||||
* * \e array \b perms Permission array
|
||||
* * \e int \b automatic 0 or 1
|
||||
* * \e srtring \b role
|
||||
*/
|
||||
static public function connect_perms($channel_id) {
|
||||
|
||||
@@ -230,70 +231,6 @@ class Permissions {
|
||||
}
|
||||
}
|
||||
|
||||
// look up the permission role to see if it specified auto-connect
|
||||
// and if there was no permcat or a default permcat, set the perms
|
||||
// from the role
|
||||
/*
|
||||
$role = get_pconfig($channel_id, 'system', 'permissions_role');
|
||||
if ($role) {
|
||||
$xx = PermissionRoles::role_perms($role);
|
||||
if ($xx['perms_auto'])
|
||||
$automatic = 1;
|
||||
|
||||
if ((!$my_perms) && ($xx['perms_connect'])) {
|
||||
$default_perms = $xx['perms_connect'];
|
||||
$my_perms = Permissions::FilledPerms($default_perms);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// If we reached this point without having any permission information,
|
||||
// it is likely a custom permissions role. First see if there are any
|
||||
// automatic permissions.
|
||||
/*
|
||||
if (!$my_perms) {
|
||||
$m = Permissions::FilledAutoperms($channel_id);
|
||||
if ($m) {
|
||||
$automatic = 1;
|
||||
$my_perms = $m;
|
||||
}
|
||||
}
|
||||
*/
|
||||
// If we reached this point with no permissions, the channel is using
|
||||
// custom perms but they are not automatic. They will be stored in abconfig with
|
||||
// the channel's channel_hash (the 'self' connection).
|
||||
|
||||
/*
|
||||
if (!$my_perms) {
|
||||
$r = q("select channel_hash from channel where channel_id = %d",
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r) {
|
||||
$x = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'my_perms'",
|
||||
intval($channel_id),
|
||||
dbesc($r[0]['channel_hash'])
|
||||
);
|
||||
if ($x) {
|
||||
foreach ($x as $xv) {
|
||||
$my_perms[$xv['k']] = intval($xv['v']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return (['perms' => $my_perms, 'automatic' => $automatic, 'role' => $pc]);
|
||||
}
|
||||
/*
|
||||
static public function serialise($p) {
|
||||
$n = [];
|
||||
if ($p) {
|
||||
foreach ($p as $k => $v) {
|
||||
if (intval($v)) {
|
||||
$n[] = $k;
|
||||
}
|
||||
}
|
||||
}
|
||||
return implode(',', $n);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -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,8 @@ namespace Zotlabs\Daemon;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\ASCollection;
|
||||
use Zotlabs\Lib\ASCache;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Convo {
|
||||
|
||||
@@ -12,52 +14,77 @@ 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;
|
||||
$interval = Config::Get('queueworker', 'queue_interval', 500000);
|
||||
|
||||
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) {
|
||||
$network_fetch = false;
|
||||
|
||||
if (is_string($message)) {
|
||||
$cached = ASCache::Get($message);
|
||||
if ($cached) {
|
||||
// logger('convo_cached: ' . $message);
|
||||
$data = $cached;
|
||||
}
|
||||
else {
|
||||
// logger('convo_fetching: ' . $message);
|
||||
$network_fetch = true;
|
||||
|
||||
$data = Activity::fetch($message, $channel);
|
||||
if ($data) {
|
||||
ASCache::Set($message, $data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
$data = $message;
|
||||
}
|
||||
|
||||
if (!$network_fetch) {
|
||||
// Add some delay so that the DB will not be overwhelmed
|
||||
// Fetched from network will already have a slight delay
|
||||
usleep($interval);
|
||||
}
|
||||
|
||||
$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;
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use DBA;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\ObjCache;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
|
||||
@@ -92,7 +94,7 @@ class Cron {
|
||||
// delete expired access tokens
|
||||
|
||||
$r = q("select atoken_id from atoken where atoken_expires > '%s' and atoken_expires < %s",
|
||||
dbesc(NULL_DATE),
|
||||
dbesc(DBA::$dba->get_null_date()),
|
||||
db_utcnow()
|
||||
);
|
||||
if ($r) {
|
||||
@@ -125,14 +127,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)) {
|
||||
@@ -235,6 +238,73 @@ class Cron {
|
||||
if (!$restart)
|
||||
Master::Summon(array('Cronhooks'));
|
||||
|
||||
|
||||
// move as obj cache to fs
|
||||
if (!Config::Get('system', 'as_objects_moved')) {
|
||||
$results = dbq("select iconfig.*, item.mid from iconfig left join item on iid = item.id where cat = 'activitypub' and k = 'rawmsg' limit 300");
|
||||
if ($results) {
|
||||
foreach ($results as $result) {
|
||||
if (is_string($result['v'])) {
|
||||
if (str_starts_with($result['v'], '{')) {
|
||||
$result['v'] = json_decode($result['v'], true);
|
||||
}
|
||||
|
||||
elseif (str_starts_with($result['v'], 'json:')) {
|
||||
$result['v'] = json_unserialize($result['v']);
|
||||
}
|
||||
|
||||
elseif (preg_match('|^a:[0-9]+:{.*}$|s', $result['v'])) {
|
||||
$result['v'] = unserialize($result['v'], ['allowed_classes' => false]);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($result['v'])) {
|
||||
ObjCache::Set($result['mid'], $result['v']);
|
||||
}
|
||||
|
||||
q("delete from iconfig where id = %d",
|
||||
intval($result['id'])
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Config::Set('system', 'as_objects_moved', 1);
|
||||
}
|
||||
}
|
||||
|
||||
// move diaspora obj cache to fs
|
||||
if (!Config::Get('system', 'diaspora_objects_moved')) {
|
||||
$results = dbq("select iconfig.*, item.mid from iconfig left join item on iid = item.id where cat = 'diaspora' and k = 'fields' limit 300");
|
||||
if ($results) {
|
||||
foreach ($results as $result) {
|
||||
if (is_string($result['v'])) {
|
||||
if (str_starts_with($result['v'], '{')) {
|
||||
$result['v'] = json_decode($result['v'], true);
|
||||
}
|
||||
|
||||
elseif (str_starts_with($result['v'], 'json:')) {
|
||||
$result['v'] = json_unserialize($result['v']);
|
||||
}
|
||||
|
||||
elseif (preg_match('|^a:[0-9]+:{.*}$|s', $result['v'])) {
|
||||
$result['v'] = unserialize($result['v'], ['allowed_classes' => false]);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($result['v'])) {
|
||||
ObjCache::Set($result['mid'], $result['v'], 'diaspora');
|
||||
}
|
||||
|
||||
q("delete from iconfig where id = %d",
|
||||
intval($result['id'])
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Config::Set('system', 'diaspora_objects_moved', 1);
|
||||
}
|
||||
}
|
||||
|
||||
Config::Set('system', 'lastcron', datetime_convert());
|
||||
|
||||
//All done - clear the lockfile
|
||||
|
||||
@@ -74,6 +74,8 @@ class Externals {
|
||||
}
|
||||
}
|
||||
|
||||
$attempts++;
|
||||
|
||||
if (!$url) {
|
||||
continue;
|
||||
}
|
||||
@@ -85,7 +87,6 @@ class Externals {
|
||||
$blacklisted = true;
|
||||
}
|
||||
|
||||
$attempts++;
|
||||
|
||||
// make sure we can eventually break out if somebody blacklists all known sites
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ class Fetchparents {
|
||||
Activity::fetch_and_store_parents($channel, $observer_hash, $mid, null, $force);
|
||||
}
|
||||
|
||||
Activity::init_background_fetch($observer_hash);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\IConfig;
|
||||
use Zotlabs\Lib\ObjCache;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Queue;
|
||||
|
||||
@@ -264,7 +266,6 @@ class Notifier {
|
||||
}
|
||||
|
||||
if (!item_forwardable($target_item)) {
|
||||
//hz_syslog(print_r($target_item,true));
|
||||
logger('notifier: target item not forwardable', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
@@ -317,10 +318,15 @@ class Notifier {
|
||||
return;
|
||||
}
|
||||
|
||||
$m = get_iconfig($target_item, 'activitypub', 'signed_data');
|
||||
$m = ObjCache::Get($target_item['mid']);
|
||||
|
||||
if (!$m) {
|
||||
$m = IConfig::Get($target_item, 'activitypub', 'rawmsg');
|
||||
}
|
||||
|
||||
// Re-use existing signature unless the activity type changed to a Tombstone, which won't verify.
|
||||
if ($m && (!intval($target_item['item_deleted']))) {
|
||||
self::$encoded_item = json_decode($m, true);
|
||||
self::$encoded_item = $m;
|
||||
}
|
||||
else {
|
||||
$activity = Activity::encode_activity($target_item);
|
||||
|
||||
@@ -9,10 +9,14 @@ class Onedirsync {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if ($argc < 2 || is_int($argv[1]) === false) {
|
||||
logger('onedirsync: no update id');
|
||||
return;
|
||||
}
|
||||
|
||||
logger('onedirsync: start ' . intval($argv[1]));
|
||||
|
||||
if (($argc > 1) && (intval($argv[1])))
|
||||
$update_id = intval($argv[1]);
|
||||
$update_id = intval($argv[1]);
|
||||
|
||||
if (!$update_id) {
|
||||
logger('onedirsync: no update id');
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use DBA;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\ASCollection;
|
||||
@@ -15,10 +16,14 @@ class Onepoll {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if ($argc < 2 || is_int($argv[1]) === false) {
|
||||
logger('onepoll: no contact');
|
||||
return;
|
||||
}
|
||||
|
||||
logger('onepoll: start');
|
||||
|
||||
if (($argc > 1) && (intval($argv[1])))
|
||||
$contact_id = intval($argv[1]);
|
||||
$contact_id = intval($argv[1]);
|
||||
|
||||
if (!$contact_id) {
|
||||
logger('onepoll: no contact');
|
||||
@@ -34,7 +39,7 @@ class Onepoll {
|
||||
$contacts = q("SELECT abook.*, xchan.* FROM abook
|
||||
LEFT JOIN xchan ON xchan_hash = abook_xchan
|
||||
WHERE abook_id = %d",
|
||||
intval($contact_id)
|
||||
$contact_id
|
||||
);
|
||||
|
||||
if (!$contacts) {
|
||||
@@ -53,7 +58,7 @@ class Onepoll {
|
||||
|
||||
logger("onepoll: poll: ($contact_id) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
|
||||
|
||||
$last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE))
|
||||
$last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= DBA::$dba->get_null_date()))
|
||||
? datetime_convert('UTC', 'UTC', 'now - 7 days')
|
||||
: datetime_convert('UTC', 'UTC', $contact['abook_updated'] . ' - 2 days')
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use DBA;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Poller {
|
||||
@@ -117,7 +118,7 @@ class Poller {
|
||||
|
||||
// if we've never connected with them, start the mark for death countdown from now
|
||||
|
||||
if ($c <= NULL_DATE) {
|
||||
if ($c <= DBA::$dba->get_null_date()) {
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
@@ -173,7 +174,7 @@ class Poller {
|
||||
|
||||
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
$r = q("SELECT * FROM updates WHERE ud_update = 1 AND (ud_last = '%s' OR ud_last > %s - INTERVAL %s)",
|
||||
dbesc(NULL_DATE),
|
||||
dbesc(DBA::$dba->get_null_date()),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('7 DAY')
|
||||
);
|
||||
@@ -184,7 +185,7 @@ class Poller {
|
||||
// If they didn't respond when we attempted before, back off to once a day
|
||||
// After 7 days we won't bother anymore
|
||||
|
||||
if ($rr['ud_last'] > NULL_DATE)
|
||||
if ($rr['ud_last'] > DBA::$dba->get_null_date())
|
||||
if ($rr['ud_last'] > datetime_convert('UTC', 'UTC', 'now - 1 day'))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -1,15 +1,57 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Hubzilla Community
|
||||
* SPDX-FileContributor: redmatrix
|
||||
* SPDX-FileContributor: Klaus Weidenbach
|
||||
* SPDX-FileContributor: zotlabs
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Extend;
|
||||
|
||||
use App;
|
||||
|
||||
/**
|
||||
* @brief Hook class.
|
||||
* A class for hooking into Hubzilla.
|
||||
*
|
||||
* Hooks are functions that Hubzilla will invoke at certain points in the code
|
||||
* during execution. An addon can register a callback handler that will be
|
||||
* called whenever the specified hook is invoked. A callback handler is a
|
||||
* function that takes a reference to an array containing the callback
|
||||
* arguments as it's only argument.
|
||||
*
|
||||
* @see call_hooks
|
||||
* @see load_hooks
|
||||
*/
|
||||
class Hook {
|
||||
|
||||
/**
|
||||
* Register a callback handler for a hook.
|
||||
*
|
||||
* A callback handler is a function that takes a reference to an array
|
||||
* containing the callback arguments as it's only argument.
|
||||
*
|
||||
* The contents and meaning of the array depends on the hook invoked. By
|
||||
* modifying the contents of the array the hook can pass data back to the
|
||||
* caller.
|
||||
*
|
||||
* Once the `Hook::register` function has been called, the callback may be
|
||||
* invoked.
|
||||
*
|
||||
* @param string $hook The name of the hook to register a handler for.
|
||||
* @param string $file The source file of the callback handler.
|
||||
* @param string|array $function
|
||||
* The function name of the callback handler, as a
|
||||
* string or an array.
|
||||
* @param int $version Hook interface version, allways 1.
|
||||
* @param int $priority The priority of the callback handler, higher
|
||||
* numbers takes precedence.
|
||||
*
|
||||
* @return true if the handler was already registered, otherwise the result
|
||||
* from inserting the hook in the database.
|
||||
*/
|
||||
static public function register($hook,$file,$function,$version = 1,$priority = 0) {
|
||||
if(is_array($function)) {
|
||||
$function = serialize($function);
|
||||
@@ -45,6 +87,14 @@ class Hook {
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an array of hook callback handlers.
|
||||
*
|
||||
* All of the handlers must be in the same source file.
|
||||
*
|
||||
* @param string $file The source file of the callback handlers.
|
||||
* @param array $arr An array of `hookname => functionname` pairs.
|
||||
*/
|
||||
static public function register_array($file,$arr) {
|
||||
if($arr) {
|
||||
foreach($arr as $k => $v) {
|
||||
@@ -54,6 +104,20 @@ class Hook {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unregister a hook callback handler.
|
||||
*
|
||||
* @param string $hook The name of the hook to register a callback handler for.
|
||||
* @param string $file The source file of the hook callback handler.
|
||||
* @param string|array $function
|
||||
* The function name of the callback handler, as a
|
||||
* string or an array.
|
||||
* @param int $version Hook interface version, allways 1.
|
||||
* @param int $priority The priority of the callback handler, higher
|
||||
* numbers takes precedence.
|
||||
*
|
||||
* @return The result of the database delete operation.
|
||||
*/
|
||||
static public function unregister($hook,$file,$function,$version = 1,$priority = 0) {
|
||||
if(is_array($function)) {
|
||||
$function = serialize($function);
|
||||
@@ -70,11 +134,13 @@ class Hook {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unregister all hooks with this file component.
|
||||
* Unregister all hooks handlers from a given source file.
|
||||
*
|
||||
* Useful for addon upgrades where you want to clean out old interfaces.
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $file The source file where the hook handlers were defined.
|
||||
*
|
||||
* @return The result from the database delete operation.
|
||||
*/
|
||||
static public function unregister_by_file($file) {
|
||||
$r = q("DELETE FROM hook WHERE file = '%s' ",
|
||||
@@ -85,25 +151,20 @@ class Hook {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a hook into a page request.
|
||||
* Inserts a hook into a page request.
|
||||
*
|
||||
* Insert a short-lived hook into the running page request.
|
||||
* Hooks are normally persistent so that they can be called
|
||||
* across asynchronous processes such as delivery and poll
|
||||
* processes.
|
||||
* Insert a short-lived hook into the running page request. Hooks are
|
||||
* normally persistent so that they can be called across asynchronous
|
||||
* processes such as delivery and poll processes.
|
||||
*
|
||||
* insert_hook lets you attach a hook callback immediately
|
||||
* which will not persist beyond the life of this page request
|
||||
* or the current process.
|
||||
* This function lets you attach a hook callback immediately which will not
|
||||
* persist beyond the life of this page request or the current process.
|
||||
*
|
||||
* @param string $hook
|
||||
* name of hook to attach callback
|
||||
* @param string $fn
|
||||
* function name of callback handler
|
||||
* @param int $version
|
||||
* hook interface version, 0 uses two callback params, 1 uses one callback param
|
||||
* @param int $priority
|
||||
* currently not implemented in this function, would require the hook array to be resorted
|
||||
* @param string $hook Name of hook to attach callback.
|
||||
* @param string|array $fn Name of callback handler as a string or array.
|
||||
* @param int $version Hook interface version, allways 1.
|
||||
* @param int $priority Currently not implemented in this function,
|
||||
* would require the hook array to be resorted.
|
||||
*/
|
||||
static public function insert($hook, $fn, $version = 0, $priority = 0) {
|
||||
if(is_array($fn)) {
|
||||
@@ -119,4 +180,4 @@ class Hook {
|
||||
App::$hooks[$hook][] = array('', $fn, $priority, $version);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,106 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018 The Hubzilla Community
|
||||
* SPDX-FileContributor: Zotlabs
|
||||
* SPDX-FileContributor: Mario <mario@mariovavti.com>
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Extend;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
/**
|
||||
* Class for managing routes.
|
||||
*
|
||||
* Routes connect a URL path to a module that will handle requests to that
|
||||
* path.
|
||||
*
|
||||
* For example by registering a route like this:
|
||||
*
|
||||
* ```php
|
||||
* Route::register(
|
||||
* __DIR__ . '/Mod_Myroute.php',
|
||||
* 'myroute'
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* Hubzilla will direct requests to the '/myroute' URL path to the 'Myroute'
|
||||
* controller located in the '/Mod_Myroute.php' file in the same directory as
|
||||
* the file this code was called from.
|
||||
*
|
||||
* Routes are stored persistently, so this function will typically be called from
|
||||
* the `<addon>_load()` function if called from an addon. Accordingly, the route must
|
||||
* be unregistered when no longer needed, like this:
|
||||
*
|
||||
* ```php
|
||||
* Route::unregister(
|
||||
* __DIR__ . '/Mod_Myroute.php',
|
||||
* 'myroute'
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* This will typically be called from the `<addon>_unload()` function in an addon.
|
||||
*/
|
||||
class Route {
|
||||
|
||||
static function register($file,$modname) {
|
||||
/**
|
||||
* Register a new route.
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
* Route::register(
|
||||
* __DIR__ . '/Mod_Myroute.php',
|
||||
* 'myroute'
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* The route is stored persistently, and must be unregistered when no longer needed.
|
||||
*
|
||||
* @param string $file The file containing the controller for handling requests to this route.
|
||||
* @param string $modname The name of the module (URL path).
|
||||
*
|
||||
* @see {@link Zotlabs::Extend::Route.unregister() unregister()}
|
||||
* @see {@link Zotlabs::Extend::Route.unregister_by_file() unregister_by_file()}
|
||||
*/
|
||||
public static function register(string $file, string $modname): void {
|
||||
$rt = self::get();
|
||||
|
||||
foreach ($rt as $r) {
|
||||
if ($r[0] === $file && $r[1] === $modname) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$rt[] = [ $file, $modname ];
|
||||
self::set($rt);
|
||||
}
|
||||
|
||||
static function unregister($file,$modname) {
|
||||
/**
|
||||
* Unregister a route.
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
* Route::unregister(
|
||||
* __DIR__ . '/Mod_Myroute.php',
|
||||
* 'myroute'
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @param string $file The file containing the controller for handling requests to this route.
|
||||
* @param string $modname The name of the module (URL path).
|
||||
*
|
||||
* @see {@link Zotlabs::Extend::Route.register() register()}
|
||||
* @see {@link Zotlabs::Extend::Route.unregister_by_file() unregister_by_file()}
|
||||
*/
|
||||
public static function unregister(string $file, string $modname): void {
|
||||
$rt = self::get();
|
||||
if($rt) {
|
||||
$n = [];
|
||||
foreach($rt as $r) {
|
||||
if($r[0] !== $file && $r[1] !== $modname) {
|
||||
if(!($r[0] === $file && $r[1] === $modname)) {
|
||||
$n[] = $r;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +108,23 @@ class Route {
|
||||
}
|
||||
}
|
||||
|
||||
static function unregister_by_file($file) {
|
||||
/**
|
||||
* Unregister all routes by source file.
|
||||
*
|
||||
* Removes all persistently stored routes with hanclers in the
|
||||
* given source file.
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
* Route::unregister_by_file(__DIR__ . '/Mod_Myroute.php');
|
||||
* ```
|
||||
*
|
||||
* @param string $file The file containing the controllers to remove.
|
||||
*
|
||||
* @see {@link Zotlabs::Extend::Route.register() register()}
|
||||
* @see {@link Zotlabs::Extend::Route.unregister() unregister()}
|
||||
*/
|
||||
public static function unregister_by_file(string $file): void {
|
||||
$rt = self::get();
|
||||
if($rt) {
|
||||
$n = [];
|
||||
@@ -38,11 +137,18 @@ class Route {
|
||||
}
|
||||
}
|
||||
|
||||
static function get() {
|
||||
/**
|
||||
* Get an array of all defined routes.
|
||||
*
|
||||
* @return An array of routes, where each entry is an array
|
||||
* containing two elements, the file, and the module
|
||||
* name.
|
||||
*/
|
||||
public static function get(): array {
|
||||
return Config::Get('system','routes',[]);
|
||||
}
|
||||
|
||||
static function set($r) {
|
||||
private static function set(array $r): mixed {
|
||||
return Config::Set('system','routes',$r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,13 @@ class Widget {
|
||||
|
||||
static function register($file,$widget) {
|
||||
$rt = self::get();
|
||||
|
||||
foreach ($rt as $r) {
|
||||
if ($r[0] === $file && $r[1] === $widget) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$rt[] = [ $file, $widget ];
|
||||
self::set($rt);
|
||||
}
|
||||
@@ -17,7 +24,7 @@ class Widget {
|
||||
if($rt) {
|
||||
$n = [];
|
||||
foreach($rt as $r) {
|
||||
if($r[0] !== $file && $r[1] !== $widget) {
|
||||
if(!($r[0] === $file && $r[1] === $widget)) {
|
||||
$n[] = $r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 json_unserialize($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, json_serialize($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;
|
||||
}
|
||||
|
||||
@@ -83,6 +95,8 @@ class ASCollection {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = null;
|
||||
|
||||
if (is_array($this->nextpage)) {
|
||||
$data = $this->nextpage;
|
||||
}
|
||||
@@ -92,7 +106,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;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,60 @@ 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);
|
||||
$this->signer = ['id' => $url];
|
||||
|
||||
$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'),
|
||||
@@ -1028,12 +1028,7 @@ class Apps {
|
||||
if(! $syslist)
|
||||
return;
|
||||
|
||||
foreach($syslist as $k => $li) {
|
||||
if($li['guid'] === $guid) {
|
||||
$position = $k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$position = array_find_key($syslist, fn ($v) => $v['guid'] === $guid);
|
||||
if(! $position)
|
||||
return;
|
||||
|
||||
@@ -1082,12 +1077,7 @@ class Apps {
|
||||
if(! $syslist)
|
||||
return;
|
||||
|
||||
foreach($syslist as $k => $li) {
|
||||
if($li['guid'] === $guid) {
|
||||
$position = $k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$position = array_find_key($syslist, fn ($v) => $v['guid'] === $guid);
|
||||
if($position >= count($syslist) - 1)
|
||||
return;
|
||||
|
||||
|
||||
@@ -132,8 +132,8 @@ class Config {
|
||||
$value = App::$config[$family][$key];
|
||||
|
||||
if (! is_array($value)) {
|
||||
if (substr($value, 0, 5) == 'json:') {
|
||||
return json_decode(substr($value, 5), true);
|
||||
if (str_starts_with($value, 'json:')) {
|
||||
return json_unserialize($value);
|
||||
} else if (preg_match('|^a:[0-9]+:{.*}$|s', $value)) {
|
||||
// Unserialize in inherently unsafe. Try to mitigate by not
|
||||
// allowing unserializing objects. Only kept for backwards
|
||||
|
||||
@@ -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?
|
||||
|
||||
|
||||
43
Zotlabs/Lib/DbStats.php
Normal file
43
Zotlabs/Lib/DbStats.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use DBA;
|
||||
|
||||
/**
|
||||
* Abstract class to obtain statistics from the database.
|
||||
*
|
||||
* This class should not be instantiated on it's own, but you can get
|
||||
* a concrete class for the configured database type of this site by
|
||||
* calling the `DbStats::getStats()` function.
|
||||
*/
|
||||
abstract class DbStats {
|
||||
|
||||
/**
|
||||
* Get an object for getting statistics from the database.
|
||||
*
|
||||
* @return DbStats The concrete class for obtaining the statistics from
|
||||
* this instances database.
|
||||
*/
|
||||
public static function getStats(): DbStats {
|
||||
return DBA::$dba->is_postgres()
|
||||
? new PostgresDbStats()
|
||||
: new MySQLDbStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of queries recorded by the database.
|
||||
*
|
||||
* @return int Number of queries.
|
||||
*/
|
||||
public abstract function getQueries(): int;
|
||||
|
||||
// Prevent instantiation of this class
|
||||
private function __construct() {}
|
||||
}
|
||||
@@ -95,8 +95,8 @@ class Enotify {
|
||||
if (array_key_exists('verb', $params['item'])) {
|
||||
// localize_item() alters the original item so make a copy first
|
||||
$i = $params['item'];
|
||||
logger('calling localize');
|
||||
localize_item($i);
|
||||
// logger('calling localize');
|
||||
// localize_item($i);
|
||||
$title = $i['title'];
|
||||
$body = $i['body'];
|
||||
$private = (($i['item_private']) || intval($i['item_obscured']));
|
||||
@@ -131,9 +131,9 @@ class Enotify {
|
||||
logger('notification: mail');
|
||||
$subject = sprintf( t('[$Projectname:Notify] New direct message received at %s'), $sitename);
|
||||
|
||||
$preamble = sprintf( t('%1$s sent you a new direct message at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$preamble = sprintf( t('%1$s sent you a new private message at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s sent you %2$s.'), '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', '[zrl=$itemlink]' . t('a direct message') . '[/zrl]');
|
||||
$sitelink = t('Please visit %s to view and/or reply to your direct messages.');
|
||||
$sitelink = t('Please visit %s to view and/or reply to your private messages.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl . '/hq/' . gen_link_id($params['item']['mid']));
|
||||
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/hq/' . gen_link_id($params['item']['mid']) . '">' . $sitename . '</a>');
|
||||
$itemlink = $siteurl . '/hq/' . gen_link_id($params['item']['mid']);
|
||||
@@ -146,7 +146,7 @@ class Enotify {
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
$action = (($moderated) ? t('requested to comment on') : t('commented on'));
|
||||
$action = (($moderated) ? t('requested to post in') : t('posted in'));
|
||||
|
||||
if(array_key_exists('item',$params)) {
|
||||
|
||||
@@ -164,8 +164,8 @@ class Enotify {
|
||||
if(activity_match($params['verb'], ['Dislike', ACTIVITY_DISLIKE]))
|
||||
$action = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_SHARE))
|
||||
$action = t('repeated');
|
||||
if(activity_match($params['verb'], [ACTIVITY_SHARE]))
|
||||
$action = (($moderated) ? t('requested to repeat') : t('repeated'));
|
||||
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ class Enotify {
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]))) {
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE, 'Announce']))) {
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
pop_lang();
|
||||
@@ -327,6 +327,9 @@ class Enotify {
|
||||
if(activity_match($params['item']['verb'], ['Dislike', ACTIVITY_DISLIKE]))
|
||||
$verb = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
if(activity_match($params['item']['verb'], [ACTIVITY_SHARE]))
|
||||
$verb = (($moderated) ? t('requested to repeat') : t('repeated'));
|
||||
|
||||
// "your post"
|
||||
if ($parent_item['author']['xchan_hash'] === $recip['channel_hash']) {
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
@@ -428,7 +431,7 @@ class Enotify {
|
||||
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_INTRO) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] Introduction received'));
|
||||
$preamble = sprintf( t('You\'ve received an new connection request from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$preamble = sprintf( t('You\'ve received a new connection request from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('You\'ve received [zrl=%1$s]a new connection request[/zrl] from %2$s.'),
|
||||
$siteurl . '/connections/ifpending',
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]');
|
||||
@@ -508,9 +511,14 @@ class Enotify {
|
||||
*/
|
||||
|
||||
|
||||
$hash = ((in_array($params['verb'], ['Create', 'Update', 'Invite'])) ? $params['item']['uuid'] : $params['item']['thr_parent_uuid']);
|
||||
|
||||
if (!$hash) {
|
||||
$hash = new_uuid();
|
||||
}
|
||||
|
||||
$datarray = [];
|
||||
$datarray['hash'] = $params['item']['uuid'] ?? new_uuid();
|
||||
$datarray['hash'] = $hash;
|
||||
$datarray['sender_hash'] = $sender['xchan_hash'];
|
||||
$datarray['xname'] = $sender['xchan_name'];
|
||||
$datarray['url'] = $sender['xchan_url'];
|
||||
@@ -569,8 +577,9 @@ class Enotify {
|
||||
dbesc($datarray['otype'])
|
||||
);
|
||||
|
||||
$r = q("select id from notify where hash = '%s' and ntype = %d and uid = %d limit 1",
|
||||
$r = q("select id from notify where hash = '%s' and link = '%s' and ntype = %d and uid = %d limit 1",
|
||||
dbesc($datarray['hash']),
|
||||
dbesc($itemlink),
|
||||
intval($datarray['ntype']),
|
||||
intval($recip['channel_id'])
|
||||
);
|
||||
@@ -848,8 +857,8 @@ class Enotify {
|
||||
}
|
||||
else {
|
||||
$itemem_text = (($item['item_thread_top'])
|
||||
? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
? (($item['obj_type'] === 'Question') ? t('started a poll') : t('started a conversation'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('posted in %s\'s conversation'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
);
|
||||
|
||||
if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
|
||||
@@ -861,12 +870,7 @@ class Enotify {
|
||||
|
||||
if($item['edited'] > $item['created']) {
|
||||
$edit = true;
|
||||
if($item['item_thread_top']) {
|
||||
$itemem_text = sprintf( t('edited a post dated %s'), relative_date($item['created']));
|
||||
}
|
||||
else {
|
||||
$itemem_text = sprintf( t('edited a comment dated %s'), relative_date($item['created']));
|
||||
}
|
||||
$itemem_text = sprintf( t('edited a message dated %s'), relative_date($item['created']));
|
||||
}
|
||||
|
||||
|
||||
@@ -886,7 +890,7 @@ class Enotify {
|
||||
'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
|
||||
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
|
||||
// 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''),
|
||||
'b64mid' => (($item['uuid']) ? $item['uuid'] : ''),
|
||||
'b64mid' => ((in_array($item['verb'] , ['Like', 'Dislike', 'Announce']) && !empty($item['thr_parent_uuid'])) ? $item['thr_parent_uuid'] : $item['uuid'] ?? ''),
|
||||
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])),
|
||||
'thread_top' => (($item['item_thread_top']) ? true : false),
|
||||
'message' => bbcode(escape_tags($itemem_text)),
|
||||
@@ -906,14 +910,13 @@ class Enotify {
|
||||
}
|
||||
|
||||
static public function format_notify($tt) {
|
||||
|
||||
$message = trim(strip_tags(bbcode($tt['msg'])));
|
||||
|
||||
if(strpos($message, $tt['xname']) === 0)
|
||||
$message = substr($message, strlen($tt['xname']) + 1);
|
||||
|
||||
$x = [
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['link'] : z_root() . '/notify/view/' . $tt['id']),
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_INTRO) ? z_root() . '/notify/view/' . $tt['id'] : $tt['link']),
|
||||
'name' => $tt['xname'],
|
||||
'url' => $tt['url'],
|
||||
'photo' => $tt['photo'],
|
||||
@@ -925,11 +928,9 @@ class Enotify {
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_intros($rr) {
|
||||
|
||||
return [
|
||||
'notify_link' => z_root() . '/connections#' . $rr['abook_id'],
|
||||
'name' => $rr['xchan_name'],
|
||||
|
||||
@@ -13,6 +13,7 @@ class IConfig {
|
||||
static public function Get(&$item, $family, $key, $default = false) {
|
||||
|
||||
$is_item = false;
|
||||
$iid = null;
|
||||
|
||||
if(is_array($item)) {
|
||||
$is_item = true;
|
||||
@@ -27,13 +28,26 @@ 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) {
|
||||
if (is_string($c['v'])) {
|
||||
if (str_starts_with($c['v'], 'json:')) {
|
||||
$c['v'] = json_unserialize($c['v']);
|
||||
} else if (preg_match('|^a:[0-9]+:{.*}$|s', $c['v'])) {
|
||||
// Unserialize in inherently unsafe. Try to mitigate by not
|
||||
// allowing unserializing objects. Only kept for backwards
|
||||
// compatibility. JSON serialization should be prefered.
|
||||
$c['v'] = unserialize($c['v'], ['allowed_classes' => false]);
|
||||
}
|
||||
}
|
||||
|
||||
return $c['v'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +56,24 @@ class IConfig {
|
||||
dbesc($family),
|
||||
dbesc($key)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
$r[0]['v'] = ((preg_match('|^a:[0-9]+:{.*}$|s',$r[0]['v'])) ? unserialize($r[0]['v']) : $r[0]['v']);
|
||||
if($is_item)
|
||||
if (str_starts_with($r[0]['v'], 'json:')) {
|
||||
$r[0]['v'] = json_unserialize($r[0]['v']);
|
||||
} else if (preg_match('|^a:[0-9]+:{.*}$|s', $r[0]['v'])) {
|
||||
// Unserialize in inherently unsafe. Try to mitigate by not
|
||||
// allowing unserializing objects. Only kept for backwards
|
||||
// compatibility. JSON serialization should be prefered.
|
||||
$r[0]['v'] = unserialize($r[0]['v'], ['allowed_classes' => false]);
|
||||
}
|
||||
|
||||
if ($is_item) {
|
||||
$item['iconfig'][] = $r[0];
|
||||
}
|
||||
|
||||
return $r[0]['v'];
|
||||
}
|
||||
|
||||
return $default;
|
||||
|
||||
}
|
||||
@@ -71,7 +97,7 @@ class IConfig {
|
||||
|
||||
static public function Set(&$item, $family, $key, $value, $sharing = false) {
|
||||
|
||||
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
|
||||
$dbvalue = ((is_array($value)) ? json_serialize($value) : $value);
|
||||
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
|
||||
|
||||
$is_item = false;
|
||||
|
||||
@@ -25,18 +25,18 @@ class Img_filesize {
|
||||
|
||||
|
||||
static function getLocalFileSize($url) {
|
||||
|
||||
|
||||
$fname = basename($url);
|
||||
$resolution = 0;
|
||||
|
||||
|
||||
if(strpos($fname,'.') !== false)
|
||||
$fname = substr($fname,0,strpos($fname,'.'));
|
||||
|
||||
|
||||
if(substr($fname,-2,1) == '-') {
|
||||
$resolution = intval(substr($fname,-1,1));
|
||||
$fname = substr($fname,0,-2);
|
||||
}
|
||||
|
||||
|
||||
$r = q("SELECT filesize FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
|
||||
dbesc($fname),
|
||||
intval($resolution)
|
||||
@@ -116,7 +116,6 @@ function getRemoteFileSize($url)
|
||||
|
||||
curl_exec($ch);
|
||||
curl_getinfo($ch);
|
||||
curl_close($ch);
|
||||
|
||||
return $size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ class LDSignatures {
|
||||
|
||||
|
||||
static function verify($data,$pubkey) {
|
||||
$expand_and_check_unsafe = true;
|
||||
|
||||
$ohash = self::hash(self::signable_options($data['signature']));
|
||||
$dhash = self::hash(self::signable_data($data));
|
||||
$ohash = self::hash(self::signable_options($data['signature']), $expand_and_check_unsafe);
|
||||
$dhash = self::hash(self::signable_data($data), $expand_and_check_unsafe);
|
||||
|
||||
$x = Crypto::verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey);
|
||||
logger('LD-verify: ' . intval($x));
|
||||
@@ -74,11 +75,11 @@ class LDSignatures {
|
||||
return json_encode($newopts,JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
static function hash($obj) {
|
||||
return hash('sha256', self::normalise($obj));
|
||||
static function hash($obj, $expand_and_check_unsafe = false) {
|
||||
return hash('sha256', self::normalise($obj, $expand_and_check_unsafe));
|
||||
}
|
||||
|
||||
static function normalise($data) {
|
||||
static function normalise($data, $expand_and_check_unsafe) {
|
||||
$ret = '';
|
||||
|
||||
if(is_string($data)) {
|
||||
@@ -90,6 +91,15 @@ class LDSignatures {
|
||||
|
||||
jsonld_set_document_loader('jsonld_document_loader');
|
||||
|
||||
if ($expand_and_check_unsafe) {
|
||||
$expanded = jsonld_expand($data);
|
||||
|
||||
if (self::contains_unsafe_keys($expanded)) {
|
||||
logger('contains_unsafe_keys: ' . print_r($data,true));
|
||||
throw new \Exception('json-ld graph modification operation detected');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$ret = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
|
||||
}
|
||||
@@ -132,6 +142,41 @@ class LDSignatures {
|
||||
|
||||
}
|
||||
|
||||
static function contains_unsafe_keys(array|object $data, int $depth = 0): bool
|
||||
{
|
||||
if ($depth > 64) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$unsafe_keys = ['@graph', '@included', '@reverse'];
|
||||
|
||||
if (is_object($data)) {
|
||||
$data = (array) $data;
|
||||
}
|
||||
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $key => $value) {
|
||||
//
|
||||
// We can't use `in_array` since the keys may contain more than
|
||||
// just the keyword after expansion, typically "_:@included"
|
||||
// for an unnamed node with the "@included" key.
|
||||
//
|
||||
// So we use `array_filter` with a callback instead:
|
||||
$matches = array_filter($unsafe_keys, fn ($k) => strpos($key, $k) !== false);
|
||||
|
||||
if (!empty($matches)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_array($value) || is_object($value)) {
|
||||
if (self::contains_unsafe_keys($value, $depth + 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -199,8 +199,7 @@ class Libsync {
|
||||
dbesc($sender)
|
||||
);
|
||||
|
||||
$mid = 'sync';
|
||||
|
||||
$mid = $arr['item'][0]['message_id'] ?? 'sync';
|
||||
|
||||
$DR = new DReport(z_root(), $sender, $d, $mid);
|
||||
|
||||
@@ -306,15 +305,8 @@ class Libsync {
|
||||
|
||||
if (array_key_exists('item', $arr) && $arr['item']) {
|
||||
sync_items($channel, $arr['item'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null));
|
||||
$mid = $arr['item'][0]['message_id'] . '#sync';
|
||||
}
|
||||
|
||||
// deprecated, maintaining for a few months for upward compatibility
|
||||
// this should sync webpages, but the logic is a bit subtle
|
||||
|
||||
//if (array_key_exists('item_id', $arr) && $arr['item_id'])
|
||||
// sync_items($channel, $arr['item_id']);
|
||||
|
||||
if (array_key_exists('menu', $arr) && $arr['menu'])
|
||||
sync_menus($channel, $arr['menu']);
|
||||
|
||||
@@ -757,12 +749,11 @@ class Libsync {
|
||||
*/
|
||||
call_hooks('process_channel_sync_delivery', $addon);
|
||||
|
||||
$DR = new DReport(z_root(), $d, $d, $mid, 'channel sync processed');
|
||||
|
||||
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
|
||||
$DR->update('channel sync processed');
|
||||
|
||||
$result[] = $DR->get();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use DBA;
|
||||
use Zotlabs\Access\PermissionLimits;
|
||||
use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
require_once('include/crypto.php');
|
||||
@@ -116,10 +116,6 @@ class Libzot {
|
||||
}
|
||||
|
||||
if ($msg) {
|
||||
$actors = get_hubloc_id_urls_by_x($channel['channel_hash']);
|
||||
if ($encoding === 'activitystreams' && array_key_exists('actor', $msg) && is_string($msg['actor']) && in_array($msg['actor'], $actors)) {
|
||||
$msg = JSalmon::sign($msg, $actors[0], $channel['channel_prvkey']);
|
||||
}
|
||||
$data['data'] = $msg;
|
||||
}
|
||||
else {
|
||||
@@ -353,7 +349,7 @@ class Libzot {
|
||||
$next_birthday = datetime_convert('UTC', 'UTC', $record['data']['profile']['next_birthday']);
|
||||
}
|
||||
else {
|
||||
$next_birthday = NULL_DATE;
|
||||
$next_birthday = DBA::$dba->get_null_date();
|
||||
}
|
||||
|
||||
$profile_assign = get_pconfig($channel['channel_id'], 'system', 'profile_assign', '');
|
||||
@@ -1302,8 +1298,17 @@ class Libzot {
|
||||
$item['comment_policy'] = 'authenticated';
|
||||
}
|
||||
|
||||
if (isset($AS->meta['signed_data']) && $AS->meta['signed_data']) {
|
||||
IConfig::Set($item, 'activitypub', 'signed_data', $AS->meta['signed_data'], false);
|
||||
if (!ObjCache::Get($item['mid'])) {
|
||||
ObjCache::Set($item['mid'], $AS->data);
|
||||
}
|
||||
else {
|
||||
$existing = q("SELECT owner_xchan, author_xchan FROM item WHERE mid = '%s' LIMIT 1",
|
||||
dbesc($item['mid'])
|
||||
);
|
||||
|
||||
if ($existing && $existing[0]['owner_xchan'] === $item['owner_xchan'] && $existing[0]['author_xchan'] === $item['author_xchan']) {
|
||||
ObjCache::Set($item['mid'], $AS->data);
|
||||
}
|
||||
}
|
||||
|
||||
logger('Activity received: ' . print_r($item, true), LOGGER_DATA, LOG_DEBUG);
|
||||
@@ -1542,6 +1547,7 @@ class Libzot {
|
||||
|
||||
$local_public = $public;
|
||||
$item_result = null;
|
||||
$parent = null;
|
||||
|
||||
$DR = new DReport(z_root(), $sender, $d, $arr['mid'], $arr['uuid']);
|
||||
|
||||
@@ -1644,12 +1650,19 @@ class Libzot {
|
||||
if (intval($channel['channel_system']) && (!$arr['item_private']) && (!$relay)) {
|
||||
$local_public = true;
|
||||
|
||||
$incl = Config::Get('system','pubstream_incl');
|
||||
$excl = Config::Get('system','pubstream_excl');
|
||||
$incl = Config::Get('system','pubstream_incl', '');
|
||||
$excl = Config::Get('system','pubstream_excl', '');
|
||||
|
||||
if(($incl || $excl) && !MessageFilter::evaluate($arr, $incl, $excl)) {
|
||||
$local_public = false;
|
||||
continue;
|
||||
if ($incl || $excl) {
|
||||
$plaintext = prepare_text($arr['body'], ((isset($arr['mimetype'])) ? $arr['mimetype'] : 'text/bbcode'));
|
||||
$plaintext = html2plain((isset($arr['summary']) && $arr['summary']) ? $arr['summary'] . ' ' . $plaintext : $plaintext);
|
||||
$plaintext = html2plain((isset($arr['title']) && $arr['title']) ? $arr['title'] . ' ' . $plaintext : $plaintext);
|
||||
|
||||
if (!(new MessageFilter($arr, html_entity_decode($incl), html_entity_decode($excl), ['plaintext' => $plaintext]))->evaluate()) {
|
||||
logger('post is filtered');
|
||||
$local_public = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$r = q("select xchan_selfcensored, xchan_censored from xchan where xchan_hash = '%s'",
|
||||
@@ -1658,6 +1671,7 @@ class Libzot {
|
||||
|
||||
// don't import sys channel posts from selfcensored or censored authors
|
||||
if ($r && ($r[0]['xchan_selfcensored'] || $r[0]['xchan_censored'])) {
|
||||
logger('author is censored');
|
||||
$local_public = false;
|
||||
continue;
|
||||
}
|
||||
@@ -1828,9 +1842,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
if (intval($arr['item_private']) === 2) {
|
||||
if (!perm_is_allowed($channel['channel_id'], $sender, 'post_mail')) {
|
||||
$allowed = false;
|
||||
}
|
||||
$allowed = perm_is_allowed($channel['channel_id'], $sender, 'post_mail');
|
||||
}
|
||||
|
||||
if (!$allowed) {
|
||||
@@ -1892,11 +1904,13 @@ class Libzot {
|
||||
else {
|
||||
$DR->update('update ignored');
|
||||
$result[] = $DR->get();
|
||||
|
||||
// We need this line to ensure wall-to-wall comments and add/remove activities are relayed (by falling through to the relay bit),
|
||||
// and at the same time not relay any other relayable posts more than once, because to do so is very wasteful.
|
||||
if (!intval($r[0]['item_origin']))
|
||||
|
||||
// The second part should prevent possible items that come back to us from channels that source our channel from being relayed again (sender != owner or author).
|
||||
if (!intval($r[0]['item_origin']) || (intval($r[0]['item_origin']) && !in_array($sender, [$r[0]['owner_xchan'], $r[0]['author_xchan']]))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1996,7 +2010,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
$DR->addto_update('relayed');
|
||||
$result[] = $DR->get();
|
||||
$result = [$DR->get()];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2147,10 +2161,9 @@ class Libzot {
|
||||
}
|
||||
|
||||
if (isset($AS->meta['signed_data'])) {
|
||||
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->meta['signed_data'], false);
|
||||
$j = json_decode($AS->meta['signed_data'], true);
|
||||
if ($j) {
|
||||
IConfig::Set($arr, 'activitypub', 'rawmsg', json_encode(JSalmon::unpack($j['data'])), true);
|
||||
ObjCache::Set($arr['mid'], json_encode(JSalmon::unpack($j['data'])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use DBA;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
@@ -216,7 +217,7 @@ class Libzotdir {
|
||||
[
|
||||
'site_url' => DIRECTORY_FALLBACK_MASTER,
|
||||
'site_flags' => DIRECTORY_MODE_PRIMARY,
|
||||
'site_update' => NULL_DATE,
|
||||
'site_update' => DBA::$dba->get_null_date(),
|
||||
'site_directory' => DIRECTORY_FALLBACK_MASTER . '/dirsearch',
|
||||
'site_realm' => DIRECTORY_REALM,
|
||||
'site_valid' => 1,
|
||||
@@ -247,7 +248,7 @@ class Libzotdir {
|
||||
|
||||
$token = Config::Get('system','realm_token');
|
||||
|
||||
$syncdate = (($rr['site_sync'] <= NULL_DATE) ? datetime_convert('UTC','UTC','now - 2 days') : $rr['site_sync']);
|
||||
$syncdate = (($rr['site_sync'] <= DBA::$dba->get_null_date()) ? datetime_convert('UTC','UTC','now - 2 days') : $rr['site_sync']);
|
||||
$x = z_fetch_url($rr['site_directory'] . '?f=&sync=' . urlencode($syncdate) . (($token) ? '&t=' . $token : ''));
|
||||
|
||||
if (! $x['success'])
|
||||
@@ -724,7 +725,7 @@ class Libzotdir {
|
||||
|
||||
if ($u) {
|
||||
$x = q("UPDATE updates SET $date_sql $flag_sql ud_last = '%s', ud_host = '%s', ud_addr = '%s', ud_update = 0 WHERE ud_id = %d",
|
||||
dbesc(NULL_DATE),
|
||||
dbesc(DBA::$dba->get_null_date()),
|
||||
dbesc(z_root()),
|
||||
dbesc($addr),
|
||||
intval($u[0]['ud_id'])
|
||||
|
||||
@@ -4,242 +4,417 @@ namespace Zotlabs\Lib;
|
||||
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
class MessageFilter {
|
||||
class MessageFilter
|
||||
{
|
||||
protected $lastMatch = '';
|
||||
protected $item = null;
|
||||
protected $include = '';
|
||||
protected $exclude = '';
|
||||
protected $options = [];
|
||||
protected $tags = null;
|
||||
protected $language = '';
|
||||
protected $text = '';
|
||||
protected $excludeRules = [];
|
||||
protected $includeRules = [];
|
||||
|
||||
public static function evaluate($item, $incl, $excl) {
|
||||
public function __construct($item, $include = '', $exclude = '', $options = [])
|
||||
{
|
||||
$this->item = $item;
|
||||
$this->include = $include;
|
||||
$this->exclude = $exclude;
|
||||
$this->options = $options;
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
|
||||
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
|
||||
protected function setup()
|
||||
{
|
||||
// Option: plaintext
|
||||
// Improve language detection by providing a plaintext version of $item['body'] which has no markup constructs/tags.
|
||||
|
||||
$lang = null;
|
||||
if (array_key_exists('plaintext', $this->options)) {
|
||||
$this->text = $this->options['plaintext'];
|
||||
} else {
|
||||
$this->text = $this->item['body'];
|
||||
}
|
||||
|
||||
if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) {
|
||||
$lang = detect_language($text);
|
||||
}
|
||||
$this->language = '';
|
||||
|
||||
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
|
||||
// Language matching is a bit tricky, because the language can be ambiguous (detect_language() returns '').
|
||||
// If the language is ambiguous, the message will pass (be accepted) regardless of language rules.
|
||||
|
||||
// exclude always has priority
|
||||
if (str_contains($this->include, 'lang=')
|
||||
|| str_contains($this->exclude, 'lang=')
|
||||
|| str_contains($this->include, 'lang!=')
|
||||
|| str_contains($this->exclude, 'lang!=')) {
|
||||
$this->language = detect_language($this->text);
|
||||
}
|
||||
|
||||
$exclude = (($excl) ? explode("\n", $excl) : null);
|
||||
$this->tags = ((isset($this->item['term']) && is_array($this->item['term'])
|
||||
&& count($this->item['term'])) ? $this->item['term'] : null);
|
||||
|
||||
if ($exclude) {
|
||||
foreach ($exclude as $word) {
|
||||
$word = html_entity_decode(trim($word));
|
||||
if (! $word) {
|
||||
continue;
|
||||
}
|
||||
if (isset($lang) && ((strpos($word, 'lang=') === 0) || (strpos($word, 'lang!=') === 0))) {
|
||||
if (!strlen($lang)) {
|
||||
// Result is ambiguous. As we are matching deny rules only at this time, continue tests.
|
||||
// Any matching deny rule concludes testing.
|
||||
continue;
|
||||
}
|
||||
if (strpos($word, 'lang=') === 0 && strcasecmp($lang, trim(substr($word, 5))) == 0) {
|
||||
return false;
|
||||
} elseif (strpos($word, 'lang!=') === 0 && strcasecmp($lang, trim(substr($word, 6))) != 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
} elseif (substr($word, 0, 1) === '$' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} elseif (substr($word, 0, 2) === '?+') {
|
||||
if (self::test_condition(substr($word, 2), $item['obj'])) {
|
||||
return false;
|
||||
}
|
||||
} elseif (substr($word, 0, 1) === '?') {
|
||||
if (self::test_condition(substr($word, 1), $item)) {
|
||||
return false;
|
||||
}
|
||||
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
|
||||
return false;
|
||||
} elseif (stristr($text, $word) !== false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->excludeRules = $this->parse($this->exclude);
|
||||
$this->includeRules = $this->parse($this->include);
|
||||
|
||||
$include = (($incl) ? explode("\n", $incl) : null);
|
||||
}
|
||||
|
||||
if ($include) {
|
||||
foreach ($include as $word) {
|
||||
$word = html_entity_decode(trim($word));
|
||||
if (! $word) {
|
||||
continue;
|
||||
}
|
||||
if (isset($lang) && ((strpos($word, 'lang=') === 0) || (strpos($word, 'lang!=') === 0))) {
|
||||
if (!strlen($lang)) {
|
||||
// Result is ambiguous. However we are checking allow rules
|
||||
// and an ambiguous language is always permitted.
|
||||
return true;
|
||||
}
|
||||
if (strpos($word, 'lang=') === 0 && strcasecmp($lang, trim(substr($word, 5))) == 0) {
|
||||
return true;
|
||||
} elseif (strpos($word, 'lang!=') === 0 && strcasecmp($lang, trim(substr($word, 6))) != 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
} elseif (substr($word, 0, 1) === '$' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} elseif (substr($word, 0, 2) === '?+') {
|
||||
if (self::test_condition(substr($word, 2), $item['obj'])) {
|
||||
return true;
|
||||
}
|
||||
} elseif (substr($word, 0, 1) === '?') {
|
||||
if (self::test_condition(substr($word, 1), $item)) {
|
||||
return true;
|
||||
}
|
||||
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
|
||||
return true;
|
||||
} elseif (stristr($text, $word) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
protected function parse($string): array
|
||||
{
|
||||
$rules = [];
|
||||
if (! strlen($string)) {
|
||||
return $rules;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
$phrases = preg_split("/(\s\|\|\s|\s&&\s|\n)/", $string, flags: PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
if (!$phrases) {
|
||||
return $rules;
|
||||
}
|
||||
for ($index = 0; $index < count($phrases); $index ++) {
|
||||
// Even indices are rules and odd indices are operations, linefeed is an implict OR.
|
||||
if (!($index & 1)) {
|
||||
$currentRule = ['operation' => '', 'rule' => $phrases[$index]];
|
||||
if ($index && isset($phrases[$index - 1])) {
|
||||
$currentRule['operation'] = $phrases[$index - 1];
|
||||
if ($currentRule['operation'] === "\n") {
|
||||
$currentRule['operation'] = ' || ';
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
$rules[] = $currentRule;
|
||||
}
|
||||
}
|
||||
return $rules;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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:
|
||||
*
|
||||
* - ?foo ~= baz which will check if item.foo contains the string 'baz';
|
||||
* - ?foo == baz which will check if item.foo is the string 'baz';
|
||||
* - ?foo != baz which will check if item.foo is not the string 'baz';
|
||||
* - ?foo >= 3 which will check if item.foo is greater than or equal to 3;
|
||||
* - ?foo > 3 which will check if item.foo is greater than 3;
|
||||
* - ?foo <= 3 which will check if item.foo is less than or equal to 3;
|
||||
* - ?foo < 3 which will check if item.foo is less than 3;
|
||||
*
|
||||
* - ?foo {} baz which will check if 'baz' is an array element in item.foo
|
||||
* - ?foo {*} baz which will check if 'baz' is an array key in item.foo
|
||||
* - ?foo which will check for a return of a true condition for item.foo;
|
||||
|
||||
public function evaluate(): bool
|
||||
{
|
||||
|
||||
$previousResult = $newResult = null;
|
||||
|
||||
// exclude always has priority
|
||||
|
||||
$exclude = $this->excludeRules;
|
||||
$include = $this->includeRules;
|
||||
|
||||
if ($exclude) {
|
||||
foreach ($exclude as $rule) {
|
||||
if (!strlen(trim($rule['rule']))) {
|
||||
continue;
|
||||
}
|
||||
if (!strlen($this->language) && ((str_starts_with($rule['rule'], 'lang=')) || (str_starts_with($rule['rule'], 'lang!=')))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = $this->evaluateRule($rule['rule']);
|
||||
|
||||
switch ($rule['operation']) {
|
||||
case '':
|
||||
$previousResult = $newResult = $result;
|
||||
break;
|
||||
case ' || ':
|
||||
$newResult = $previousResult || $result;
|
||||
break;
|
||||
case ' && ':
|
||||
$newResult = $previousResult && $result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($newResult) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$previousResult = $newResult = null;
|
||||
|
||||
if ($include) {
|
||||
foreach ($include as $rule) {
|
||||
if (!strlen(trim($rule['rule']))) {
|
||||
continue;
|
||||
}
|
||||
if (!strlen($this->language) && ((str_starts_with($rule['rule'], 'lang=')) || (str_starts_with($rule['rule'], 'lang!=')))) {
|
||||
continue;
|
||||
}
|
||||
$result = $this->evaluateRule($rule['rule']);
|
||||
|
||||
switch ($rule['operation']) {
|
||||
case '':
|
||||
$previousResult = $newResult = $result;
|
||||
break;
|
||||
case ' || ':
|
||||
$newResult = $previousResult || $result;
|
||||
break;
|
||||
case ' && ':
|
||||
$newResult = $previousResult && $result;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return $newResult ?? true;
|
||||
}
|
||||
|
||||
protected function evaluateRule($ruleText): bool
|
||||
{
|
||||
$ruleText = trim($ruleText);
|
||||
|
||||
if (($this->language) && ((str_starts_with($ruleText, 'lang=')) || (str_starts_with($ruleText, 'lang!=')))) {
|
||||
if (str_starts_with($ruleText, 'lang=') && strcasecmp($this->language, trim(substr($ruleText, 5))) == 0) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
} elseif (str_starts_with($ruleText, 'lang!=') && strcasecmp($this->language, trim(substr($ruleText, 6))) != 0) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
} elseif (str_starts_with($ruleText, 'until=')) {
|
||||
$until = strtotime(trim(substr($ruleText, 6)));
|
||||
|
||||
if ($until > strtotime($this->item['created'] . ' UTC')) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
} elseif (str_starts_with($ruleText, '#') && $this->tags) {
|
||||
// #hashtag match
|
||||
foreach ($this->tags as $t) {
|
||||
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (!strcasecmp($t['term'], substr($ruleText, 1)) || (substr($ruleText, 1) === '*'))) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// hashtag count match
|
||||
if (substr($ruleText, 1, 1) === '>') {
|
||||
$hashtagLimit = (int)substr($ruleText, 2);
|
||||
$hashtagCount = 0;
|
||||
foreach ($this->tags as $t) {
|
||||
if ($t['ttype'] == TERM_HASHTAG || $t['ttype'] == TERM_COMMUNITYTAG) {
|
||||
$hashtagCount++;
|
||||
}
|
||||
}
|
||||
if ($hashtagLimit && $hashtagCount > $hashtagLimit) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} elseif (str_starts_with($ruleText, '@') && $this->tags) {
|
||||
// @mention match
|
||||
foreach ($this->tags as $t) {
|
||||
if ((($t['ttype'] == TERM_MENTION && (!strcasecmp($t['term'], substr($ruleText, 1)))) || (substr($ruleText, 1) === '*'))) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// mention count match
|
||||
if (substr($ruleText, 1, 1) === '>') {
|
||||
$mentionLimit = (int)substr($ruleText, 2);
|
||||
$mentionCount = 0;
|
||||
foreach ($this->tags as $t) {
|
||||
if ($t['ttype'] == TERM_MENTION) {
|
||||
$mentionCount++;
|
||||
}
|
||||
}
|
||||
if ($mentionLimit && $mentionCount > $mentionLimit) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} elseif (str_starts_with($ruleText, '$') && $this->tags) {
|
||||
foreach ($this->tags as $t) {
|
||||
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($ruleText, 1)) || (substr($ruleText, 1) === '*'))) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} elseif (str_starts_with($ruleText, '?+') && is_array($this->item['obj'])) {
|
||||
if ($this->test_condition(substr($ruleText, 2), $this->item['obj'])) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
} elseif (str_starts_with($ruleText, '?')) {
|
||||
$this->item['ua'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
|
||||
if (empty($this->item['app'])) {
|
||||
$author_app = $this->item['author']['site_project'] ?? '';
|
||||
if (!$author_app && isset($this->item['author'])) {
|
||||
if (str_contains($this->item['author']['xchan_hash'], 'threads.net') || str_contains($this->item['author']['xchan_hash'], 'threads.com')) {
|
||||
$author_app = 'threads';
|
||||
}
|
||||
}
|
||||
$this->item['app'] = $author_app;
|
||||
}
|
||||
if ($this->test_condition(substr($ruleText, 1), $this->item)) {
|
||||
unset($this->item['ua']);
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
unset($this->item['ua']);
|
||||
} elseif ((str_starts_with($ruleText, '/')) && preg_match($ruleText, $this->item['body'])) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
} elseif (stristr($this->item['body'], $ruleText) !== false) {
|
||||
$this->lastMatch = $ruleText;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function getLastMatch(): string
|
||||
{
|
||||
return $this->lastMatch;
|
||||
}
|
||||
public function setLastMatch($string): MessageFilter
|
||||
{
|
||||
$this->lastMatch = $string;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @brief Test for Conditional Execution conditions. Shamelessly ripped off from src/Render/Comanche
|
||||
*
|
||||
* This is extensible. The first version of variable testing supports tests of the forms:
|
||||
*
|
||||
* - ?foo ~= baz will check if item.foo contains the string 'baz';
|
||||
* - ?foo == baz will check if item.foo is the string 'baz';
|
||||
* - ?foo != baz will check if item.foo is not the string 'baz';
|
||||
* - ?foo // baz will check if item.foo matches the regular expression 'baz';
|
||||
* - ?foo >= 3 will check if item.foo is greater than or equal to 3;
|
||||
* - ?foo > 3 will check if item.foo is greater than 3;
|
||||
* - ?foo <= 3 will check if item.foo is less than or equal to 3;
|
||||
* - ?foo < 3 will check if item.foo is less than 3;
|
||||
* - ?foo & 2 will check if item.foo has the second bit set.
|
||||
* - ?foo !& 2 will check if item.foo does not have the second bit set.
|
||||
*
|
||||
* - ?foo {} baz which will check if 'baz' is an array element in item.foo
|
||||
* - ?foo {*} baz which will check if 'baz' is an array key in item.foo
|
||||
* - ?foo which will check for a return of a true condition for item.foo;
|
||||
* - ?!foo which will check for a return of a false condition for item.foo;
|
||||
*
|
||||
* The values 0, '', an empty array, and an unset value will all evaluate to false.
|
||||
*
|
||||
* @param string $s
|
||||
* @param array $item
|
||||
* @return bool
|
||||
*/
|
||||
* The values 0, '', an empty array, and an unset value will all evaluate to false.
|
||||
*
|
||||
* @param string $s
|
||||
* @param array $item
|
||||
* @return bool
|
||||
*/
|
||||
protected function test_condition($s,$item)
|
||||
{
|
||||
$s = trim($s);
|
||||
|
||||
public static function test_condition($s,$item) {
|
||||
if (preg_match('/(.*?)\s&\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x & (int) trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (preg_match('/(.*?)\s!&\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (!($x & (int) trim($matches[2]))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (preg_match('/(.*?)\s~=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (is_string($x) && stripos($x, trim($matches[2])) !== false) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (preg_match('/(.*?)\s\/\/\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (substr(trim($matches[2]),0,1) !== substr(trim($matches[2]),-1)) {
|
||||
$matches[2] = '/' . trim($matches[2]) . '/';
|
||||
}
|
||||
if (preg_match(trim($matches[2]), $x)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// Ordering of this check (for falsiness) with relation to the following one (check for truthiness) is important.
|
||||
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;
|
||||
}
|
||||
// Array contains value
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// Ordering of this check (for falseness) with relation to the following one (check for truthiness) is important.
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
37
Zotlabs/Lib/MySQLDbStats.php
Normal file
37
Zotlabs/Lib/MySQLDbStats.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use DBA;
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
* Concrete implementation for getting stats from MySQL and MariaDB databases.
|
||||
*/
|
||||
class MySQLDbStats extends DbStats {
|
||||
|
||||
public function getQueries(): int {
|
||||
//
|
||||
// We can't use the regular Hubzilla db helper function here, as
|
||||
// it will only return information from a `SELECT` statement.
|
||||
//
|
||||
// Use the basic PDO access instead.
|
||||
//
|
||||
$query = DBA::$dba->db->prepare('SHOW STATUS LIKE "Queries"');
|
||||
$query->execute();
|
||||
|
||||
$result = $query->fetch(PDO::FETCH_ASSOC);
|
||||
logger(print_r($result, true));
|
||||
if (!empty($result)) {
|
||||
return $result['Value'] ?? -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
40
Zotlabs/Lib/ObjCache.php
Normal file
40
Zotlabs/Lib/ObjCache.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
class ObjCache
|
||||
{
|
||||
public static function Get($path, $type = 'as')
|
||||
{
|
||||
if (!$path) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$localpath = Hashpath::path($path, 'store/[data]/[obj]/' . $type, 2, alg: 'sha256');
|
||||
if (file_exists($localpath)) {
|
||||
return json_unserialize(file_get_contents($localpath));
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function Set($path, $content, $type = 'as') {
|
||||
if (!$path) {
|
||||
return;
|
||||
}
|
||||
|
||||
$localpath = Hashpath::path($path, 'store/[data]/[obj]/' . $type, 2, alg: 'sha256');
|
||||
file_put_contents($localpath, json_serialize($content));
|
||||
}
|
||||
|
||||
public static function Delete($path, $type = 'as') {
|
||||
if (!$path) {
|
||||
return;
|
||||
}
|
||||
|
||||
$localpath = Hashpath::path($path, 'store/[data]/[obj]/' . $type, 2, alg: 'sha256');
|
||||
if (file_exists($localpath)) {
|
||||
unlink($localpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Zotlabs/Lib/PostgresDbStats.php
Normal file
32
Zotlabs/Lib/PostgresDbStats.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use DBA;
|
||||
|
||||
/**
|
||||
* Concrete implementation for getting stats from PostgreSQL databases.
|
||||
*/
|
||||
class PostgresDbStats extends DbStats {
|
||||
|
||||
public function getQueries(): int {
|
||||
$sqlGetQps = <<<'SQL'
|
||||
select (xact_commit + xact_rollback) as queries
|
||||
from pg_stat_database
|
||||
where datname='%s'
|
||||
SQL;
|
||||
|
||||
$result = q($sqlGetQps, DBA::$dba->dbname);
|
||||
if (!empty($result)) {
|
||||
return $result[0]['queries'] ?? -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,20 @@ use Zotlabs\Zot6\Zot6Handler;
|
||||
|
||||
class Queue {
|
||||
|
||||
/**
|
||||
* Get number of entries in the out queue.
|
||||
*
|
||||
* When delivery is successful, the item is removed from the out queue, so
|
||||
* the number of items in the queue reflects the number of pending delivery
|
||||
* attempts.
|
||||
*
|
||||
* @return int Number of items in the out queue.
|
||||
*/
|
||||
static function count(): int {
|
||||
$r = dbq('select count(*) as total from outq');
|
||||
return $r[0]['total'] ?? 0;
|
||||
}
|
||||
|
||||
static function update($id, $add_priority = 0) {
|
||||
|
||||
logger('queue: requeue item ' . $id,LOGGER_DEBUG);
|
||||
|
||||
28
Zotlabs/Lib/QueueWorkerStats.php
Normal file
28
Zotlabs/Lib/QueueWorkerStats.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
class QueueWorkerStats
|
||||
{
|
||||
public readonly int $size;
|
||||
public readonly int $active;
|
||||
|
||||
public function __construct() {
|
||||
$query = <<<'SQL'
|
||||
select count(*) as total from workerq
|
||||
union (select count(*) as qworkers from workerq where workerq_reservationid is not null)
|
||||
SQL;
|
||||
|
||||
$result = dbq('select count(*) as total from workerq');
|
||||
$this->size = !empty($result) ? $result[0]['total'] : -1;
|
||||
|
||||
$result = dbq('select count(*) as qworkers from workerq where workerq_reservationid is not null');
|
||||
$this->active = !empty($result) ? $result[0]['qworkers'] : -1;
|
||||
}
|
||||
}
|
||||
@@ -118,26 +118,28 @@ class Share {
|
||||
$photo_bb = $object['body'];
|
||||
}
|
||||
|
||||
if (strpos($this->item['body'], "[/share]") !== false) {
|
||||
$pos = strpos($this->item['body'], "[share");
|
||||
$bb = substr($this->item['body'], $pos);
|
||||
} else {
|
||||
$bb = "[share author='".urlencode($this->item['author']['xchan_name']).
|
||||
"' profile='" . $this->item['author']['xchan_url'] .
|
||||
"' avatar='" . $this->item['author']['xchan_photo_s'] .
|
||||
"' link='" . $this->item['plink'] .
|
||||
"' auth='" . (($this->item['author']['xchan_network'] === 'zot6') ? 'true' : 'false') .
|
||||
"' posted='" . $this->item['created'] .
|
||||
"' message_id='" . $this->item['mid'] .
|
||||
"']";
|
||||
if($this->item['title'])
|
||||
if (!str_contains($this->item['body'], '[/share]')) {
|
||||
$quote = in_array($this->item['author']['xchan_network'], ['zot6', 'activitypub']) ? "quote='true'" : '';
|
||||
|
||||
$bb .= "[share author='" . urlencode($this->item['author']['xchan_name']) . "'
|
||||
profile='" . $this->item['author']['xchan_url'] . "'
|
||||
avatar='" . $this->item['author']['xchan_photo_s'] . "'
|
||||
link='" . $this->item['plink'] . "'
|
||||
auth='" . (($this->item['author']['xchan_network'] === 'zot6') ? 'true' : 'false') . "'
|
||||
posted='" . $this->item['created'] . "'
|
||||
message_id='" . $this->item['mid'] . "'
|
||||
$quote
|
||||
]";
|
||||
|
||||
if ($this->item['title']) {
|
||||
$bb .= '[h3][b]'.$this->item['title'].'[/b][/h3]'."\r\n";
|
||||
}
|
||||
|
||||
$bb .= (($is_photo) ? $photo_bb . "\r\n" . $this->item['body'] : $this->item['body']);
|
||||
$bb .= "[/share]";
|
||||
}
|
||||
|
||||
return $bb;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use DBA;
|
||||
use Zotlabs\Access\AccessList;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once('include/text.php');
|
||||
|
||||
@@ -26,6 +25,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 +35,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 +63,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 +80,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 +99,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 +112,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
|
||||
@@ -123,10 +121,10 @@ class ThreadItem {
|
||||
$locktype = 0;
|
||||
}
|
||||
|
||||
$shareable = ((local_channel() && $conv->get_profile_owner() == local_channel()) && (intval($item['item_private']) === 0));
|
||||
$shareable = ((local_channel() && $conv->get_profile_owner() == local_channel()) && (intval($item['item_private']) === 0) && !str_contains($item['body'], '[/share]'));
|
||||
|
||||
// allow an exemption for sharing stuff from your private feeds
|
||||
if($item['author']['xchan_network'] === 'rss')
|
||||
if ($item['author']['xchan_network'] === 'rss')
|
||||
$shareable = true;
|
||||
|
||||
$repeatable = ((local_channel() && $conv->get_profile_owner() == local_channel()) && intval($item['item_private']) === 0 && in_array($item['author']['xchan_network'], ['zot6', 'activitypub']));
|
||||
@@ -209,9 +207,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 +220,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 +231,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 +249,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,16 +281,15 @@ 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"));
|
||||
$reactions_allowed = true;
|
||||
if($this->is_commentable()) {
|
||||
$reply_to = array( t("Reply to this message"), t("reply"), t("Reply to"));
|
||||
|
||||
if ($observer) {
|
||||
$reactions_allowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
$share = [];
|
||||
@@ -339,9 +332,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 +343,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 +357,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 +385,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,
|
||||
@@ -415,7 +416,7 @@ class ThreadItem {
|
||||
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
|
||||
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created']),
|
||||
'editedtime' => (($item['edited'] != $item['created']) ? sprintf(t('Last edited %s'), relative_time($item['edited'])) : ''),
|
||||
'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf(t('Expires %s'), relative_time($item['expires'])) : ''),
|
||||
'expiretime' => (($item['expires'] > DBA::$dba->get_null_date()) ? sprintf(t('Expires %s'), relative_time($item['expires'])) : ''),
|
||||
'lock' => $lock,
|
||||
'locktype' => $locktype,
|
||||
'delayed' => (($item['item_delayed']) ? sprintf(t('Published %s'), relative_time($item['created'])) : ''),
|
||||
@@ -431,6 +432,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 +442,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 +467,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 +485,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 +512,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 +777,7 @@ class ThreadItem {
|
||||
*/
|
||||
private function get_comment_box() {
|
||||
|
||||
if(!$this->is_toplevel() && !Config::Get('system','thread_allow')) {
|
||||
if(!$this->is_toplevel()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -803,7 +817,7 @@ class ThreadItem {
|
||||
'$eduline' => t('Underline'),
|
||||
'$edquote' => t('Quote'),
|
||||
'$edcode' => t('Code'),
|
||||
'$edimg' => t('Image'),
|
||||
'$edimg' => t('Embed (existing) photo from your photo albums'),
|
||||
'$edatt' => t('Attach/Upload file'),
|
||||
'$edurl' => t('Insert Link'),
|
||||
'$edvideo' => t('Video'),
|
||||
@@ -834,6 +848,7 @@ class ThreadItem {
|
||||
$conv = $this->get_conversation();
|
||||
$this->wall_to_wall = false;
|
||||
$this->owner_url = '';
|
||||
$this->owner_addr = '';
|
||||
$this->owner_photo = '';
|
||||
$this->owner_name = '';
|
||||
|
||||
@@ -842,12 +857,14 @@ class ThreadItem {
|
||||
|
||||
if($this->is_toplevel() && ($this->get_data_value('author_xchan') != $this->get_data_value('owner_xchan'))) {
|
||||
$this->owner_url = chanlink_hash($this->data['owner']['xchan_hash']);
|
||||
$this->owner_addr = $this->data['owner']['xchan_addr'];
|
||||
$this->owner_photo = $this->data['owner']['xchan_photo_s'];
|
||||
$this->owner_name = $this->data['owner']['xchan_name'];
|
||||
$this->wall_to_wall = true;
|
||||
}
|
||||
elseif($this->is_toplevel() && $this->get_data_value('verb') === 'Announce' && isset($this->data['source'])) {
|
||||
$this->owner_url = chanlink_hash($this->data['source']['xchan_hash']);
|
||||
$this->owner_addr = $this->data['source']['xchan_addr'];
|
||||
$this->owner_photo = $this->data['source']['xchan_photo_s'];
|
||||
$this->owner_name = $this->data['source']['xchan_name'];
|
||||
$this->wall_to_wall = true;
|
||||
@@ -862,6 +879,10 @@ class ThreadItem {
|
||||
return $this->owner_url;
|
||||
}
|
||||
|
||||
private function get_owner_addr() {
|
||||
return $this->owner_addr;
|
||||
}
|
||||
|
||||
private function get_owner_photo() {
|
||||
return $this->owner_photo;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ class ThreadStream {
|
||||
private $prepared_item = '';
|
||||
public $reload = '';
|
||||
private $cipher = 'AES-128-CCM';
|
||||
public $mid_uuid_map = [];
|
||||
public $comments_total = 0;
|
||||
public $comments_loaded = 0;
|
||||
|
||||
|
||||
// $prepared_item is for use by alternate conversation structures such as photos
|
||||
// wherein we've already prepared a top level item which doesn't look anything like
|
||||
@@ -211,16 +215,15 @@ class ThreadStream {
|
||||
* _ The data requested on success
|
||||
* _ false on failure
|
||||
*/
|
||||
public function get_template_data($conv_responses, $mid_uuid_map) {
|
||||
public function get_template_data() {
|
||||
$result = array();
|
||||
|
||||
foreach($this->threads as $item) {
|
||||
|
||||
if(($item->get_data_value('id') == $item->get_data_value('parent')) && $this->prepared_item) {
|
||||
$item_data = $this->prepared_item;
|
||||
}
|
||||
else {
|
||||
$item_data = $item->get_template_data($conv_responses, $mid_uuid_map);
|
||||
$item_data = $item->get_template_data();
|
||||
}
|
||||
if(!$item_data) {
|
||||
logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR);
|
||||
|
||||
@@ -9,7 +9,7 @@ trait HelpHelperTrait {
|
||||
// PHP versions before 8.2 does not support trait constants,
|
||||
// Leave this commented out until we drop support for PHP 8.1.
|
||||
//
|
||||
// const VALID_FILE_EXT = ['md', 'bb', 'html'];
|
||||
// const VALID_FILE_EXT = ['md', 'bb', 'html', 'json'];
|
||||
|
||||
private string $file_name = '';
|
||||
private string $file_type = '';
|
||||
@@ -58,7 +58,7 @@ trait HelpHelperTrait {
|
||||
private function find_help_file(string $base_path, string $lang): void {
|
||||
|
||||
// Use local variable until we can use trait constants.
|
||||
$valid_file_ext = ['md', 'bb', 'html'];
|
||||
$valid_file_ext = ['md', 'bb', 'html', 'json'];
|
||||
|
||||
$base_path_with_lang = "doc/{$lang}/${base_path}";
|
||||
|
||||
@@ -89,7 +89,7 @@ trait HelpHelperTrait {
|
||||
);
|
||||
|
||||
return bbcode(
|
||||
t("This page is not yet available in {$prefered_language_name}. See [observer.baseurl]/help/developer/developer_guide#Translations for information about how to help.")
|
||||
t("This page is not yet available in {$prefered_language_name}. See [observer.baseurl]/help/developer/developers_guide#Translations for information about how to help.")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
|
||||
// logger('mod_acl: ' . print_r($_GET,true),LOGGER_DATA);
|
||||
|
||||
$start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
|
||||
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500);
|
||||
$search = (x($_REQUEST,'search') ? $_REQUEST['search'] : '');
|
||||
$type = (x($_REQUEST,'type') ? $_REQUEST['type'] : '');
|
||||
$noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false);
|
||||
$start = (!empty($_REQUEST['start']) ? $_REQUEST['start'] : 0);
|
||||
$count = (!empty($_REQUEST['count']) ? $_REQUEST['count'] : 500);
|
||||
$search = (!empty($_REQUEST['search']) ? $_REQUEST['search'] : '');
|
||||
$type = (!empty($_REQUEST['type']) ? $_REQUEST['type'] : '');
|
||||
$noforums = (!empty($_REQUEST['n']) ? $_REQUEST['n'] : false);
|
||||
|
||||
|
||||
// $type =
|
||||
@@ -53,7 +53,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
// List of channels whose connections to also suggest,
|
||||
// e.g. currently viewed channel or channels mentioned in a post
|
||||
|
||||
$extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array());
|
||||
$extra_channels = (!empty($_REQUEST['extra_channels']) ? $_REQUEST['extra_channels'] : []);
|
||||
|
||||
// The different autocomplete libraries use different names for the search text
|
||||
// parameter. Internally we'll use $search to represent the search text no matter
|
||||
@@ -416,7 +416,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
$dirmode = intval(Config::Get('system','directory_mode'));
|
||||
$search = ((x($_REQUEST,'search')) ? htmlentities($_REQUEST['search'],ENT_COMPAT,'UTF-8',false) : '');
|
||||
$search = ((!empty($_REQUEST['search'])) ? htmlentities($_REQUEST['search'], ENT_COMPAT, 'UTF-8', false) : '');
|
||||
if(! $search || mb_strlen($search) < 2)
|
||||
return array();
|
||||
|
||||
@@ -446,7 +446,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
|
||||
$token = Config::Get('system','realm_token');
|
||||
|
||||
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
|
||||
$count = (!empty($_REQUEST['count']) ? $_REQUEST['count'] : 100);
|
||||
if($url) {
|
||||
$query = $url . '?f=' . (($token) ? '&t=' . urlencode($token) : '');
|
||||
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
|
||||
|
||||
@@ -23,7 +23,7 @@ class Activity extends Controller {
|
||||
if (! $item_id)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$portable_id = EMPTY_STR;
|
||||
$portable_id = null;
|
||||
|
||||
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
|
||||
dbesc(ACTIVITY_FOLLOW),
|
||||
@@ -166,6 +166,7 @@ class Activity extends Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$portable_id = null;
|
||||
$ob_authorize = false;
|
||||
$item_uid = 0;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use DBA;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once('include/account.php');
|
||||
@@ -90,7 +91,7 @@ class Admin extends \Zotlabs\Web\Controller {
|
||||
$r = q("SELECT COUNT(CASE WHEN account_id > 0 THEN 1 ELSE NULL END) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires > '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account",
|
||||
db_utcnow(),
|
||||
db_utcnow(),
|
||||
dbesc(NULL_DATE),
|
||||
dbesc(DBA::$dba->get_null_date()),
|
||||
intval(ACCOUNT_BLOCKED)
|
||||
);
|
||||
if ($r) {
|
||||
|
||||
@@ -341,29 +341,27 @@ class Accounts {
|
||||
* @SuppressWarnings(PHPMD.ShortVariable)
|
||||
*/
|
||||
private function block_unblock_accounts(): void {
|
||||
if (!isset($_POST['user']) || !isset($_POST['blocked'])) {
|
||||
if (!isset($_POST['user'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$users = $_POST['user'];
|
||||
$blocked = $_POST['blocked'];
|
||||
|
||||
if (!is_array($users) || !is_array($blocked)) {
|
||||
if (!is_array($users)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($users as $i => $id) {
|
||||
// if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
|
||||
$op = $blocked[$i] ? '& ~' : '| ';
|
||||
$xor = db_getfunc('^');
|
||||
|
||||
q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
|
||||
foreach($users as $id) {
|
||||
q("UPDATE account SET account_flags = (account_flags $xor %d) WHERE account_id = %d",
|
||||
intval(ACCOUNT_BLOCKED),
|
||||
intval($id)
|
||||
);
|
||||
}
|
||||
|
||||
$count = count($users);
|
||||
$fmt = tt("%s account blocked/unblocked", "%s account blocked/unblocked", $count);
|
||||
$fmt = tt("%s account blocked/unblocked", "%s accounts blocked/unblocked", $count);
|
||||
notice(sprintf($fmt, $count));
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ class Attach_edit extends Controller {
|
||||
$admin_delete = false;
|
||||
|
||||
$is_creator = (($creator == $observer_hash) ? true : false);
|
||||
$move = ((! $copy && ($folder !== $newfolder || (($single) ? $filename !== $newfilename : false))) ? true : false);
|
||||
$move = ((!$delete && !$copy && ($folder !== $newfolder || (($single) ? $filename !== $newfilename : false))) ? true : false);
|
||||
|
||||
$perms = get_all_perms($channel_id, $observer_hash);
|
||||
|
||||
@@ -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,';
|
||||
|
||||
}
|
||||
|
||||
@@ -83,37 +83,31 @@ class Bookmarks extends \Zotlabs\Web\Controller {
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
$o = '';
|
||||
|
||||
$o .= '<div class="generic-content-wrapper-styled">';
|
||||
|
||||
$o .= '<h3>' . t('Bookmarks') . '</h3>';
|
||||
|
||||
$x = menu_list(local_channel(),'',MENU_BOOKMARK);
|
||||
|
||||
if($x) {
|
||||
foreach($x as $xx) {
|
||||
$y = menu_fetch($xx['menu_name'],local_channel(),get_observer_hash());
|
||||
$o .= menu_render($y,'',true);
|
||||
$bookmarks = [];
|
||||
$x = menu_list(local_channel(), '', MENU_BOOKMARK);
|
||||
if ($x) {
|
||||
foreach ($x as $xx) {
|
||||
$y = menu_fetch($xx['menu_name'], local_channel(), get_observer_hash());
|
||||
$bookmarks[] = menu_render($y, '', true);
|
||||
}
|
||||
}
|
||||
|
||||
$o .= '<h3>' . t('My Connections Bookmarks') . '</h3>';
|
||||
|
||||
|
||||
$x = menu_list(local_channel(),'',MENU_SYSTEM|MENU_BOOKMARK);
|
||||
|
||||
if($x) {
|
||||
foreach($x as $xx) {
|
||||
$y = menu_fetch($xx['menu_name'],local_channel(),get_observer_hash());
|
||||
$o .= menu_render($y,'',true);
|
||||
$conn_bookmarks = [];
|
||||
$x = menu_list(local_channel(), '', MENU_SYSTEM | MENU_BOOKMARK);
|
||||
if ($x) {
|
||||
foreach ($x as $xx) {
|
||||
$y = menu_fetch($xx['menu_name'], local_channel(), get_observer_hash());
|
||||
$conn_bookmarks[] = menu_render($y, '', true);
|
||||
}
|
||||
}
|
||||
|
||||
$o .= '</div>';
|
||||
|
||||
return $o;
|
||||
|
||||
return replace_macros(get_markup_template('bookmarks.tpl'), [
|
||||
'$title1' => t('Bookmarks'),
|
||||
'$title2' => t('My Connections Bookmarks'),
|
||||
'$bookmarks' => $bookmarks,
|
||||
'$conn_bookmarks' => $conn_bookmarks,
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use DBA;
|
||||
|
||||
class Changeaddr extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -29,7 +30,7 @@ class Changeaddr extends \Zotlabs\Web\Controller {
|
||||
if(! ($x && $x['account']))
|
||||
return;
|
||||
|
||||
if($account['account_password_changed'] > NULL_DATE) {
|
||||
if($account['account_password_changed'] > DBA::$dba->get_null_date()) {
|
||||
$d1 = datetime_convert('UTC','UTC','now - 48 hours');
|
||||
if($account['account_password_changed'] > $d1) {
|
||||
notice( t('Channel name changes are not allowed within 48 hours of changing the account password.') . EOL);
|
||||
|
||||
@@ -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));
|
||||
@@ -148,14 +148,14 @@ class Channel extends Controller {
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/atom+xml',
|
||||
'title' => t('Posts and comments'),
|
||||
'href' => z_root() . '/feed/' . $which
|
||||
'href' => z_root() . '/feed/' . $which . '?top=0'
|
||||
]);
|
||||
|
||||
head_add_link([
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/atom+xml',
|
||||
'title' => t('Only posts'),
|
||||
'href' => z_root() . '/feed/' . $which . '?f=&top=1'
|
||||
'href' => z_root() . '/feed/' . $which . '?top=1'
|
||||
]);
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use DBA;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Access\AccessList;
|
||||
@@ -300,7 +301,7 @@ class Channel_calendar extends Controller {
|
||||
from event left join item on item.resource_id = event.event_hash
|
||||
where event.uid = %d and event.dtstart > '%s' and event.dtend > event.dtstart",
|
||||
intval(local_channel()),
|
||||
dbesc(NULL_DATE)
|
||||
dbesc(DBA::$dba->get_null_date())
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use DBA;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
@@ -232,7 +233,7 @@ class Dirsearch extends Controller {
|
||||
$spkt = array('transactions' => array());
|
||||
|
||||
$r = q("SELECT * FROM updates WHERE ud_update = 0 AND ud_last = '%s' AND ud_date >= '%s' ORDER BY ud_date DESC",
|
||||
dbesc(NULL_DATE),
|
||||
dbesc(DBA::$dba->get_null_date()),
|
||||
dbesc($sync)
|
||||
);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -61,12 +61,10 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = q("select * from dreport where dreport_xchan = '%s' and (dreport_mid = '%s' or dreport_mid = '%s' or dreport_mid = '%s' or dreport_mid = '%s')",
|
||||
$r = q("select * from dreport where dreport_xchan = '%s' and (dreport_mid = '%s' or dreport_mid = '%s')",
|
||||
dbesc($channel['channel_hash']),
|
||||
dbesc($mid),
|
||||
dbesc($mid . '#sync'),
|
||||
dbesc(str_replace('/item/', '/activity/', $mid)),
|
||||
dbesc(str_replace('/item/', '/activity/', $mid) . '#sync')
|
||||
dbesc(str_replace('/item/', '/activity/', $mid))
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/security.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
|
||||
class Embed extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$post_id = ((argc() > 1) ? intval(argv(1)) : 0);
|
||||
|
||||
if(! $post_id)
|
||||
killme();
|
||||
|
||||
echo '[share=' . $post_id . '][/share]';
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2,49 +2,47 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use DBA;
|
||||
use Zotlabs\Lib\PConfig;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
require_once('include/items.php');
|
||||
|
||||
class Feed extends \Zotlabs\Web\Controller {
|
||||
class Feed extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$params = [];
|
||||
|
||||
$params['begin'] = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE);
|
||||
$params['end'] = ((x($_REQUEST,'date_end')) ? $_REQUEST['date_end'] : '');
|
||||
$params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
|
||||
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
|
||||
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
|
||||
$params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0);
|
||||
$params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 10);
|
||||
$params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
|
||||
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
|
||||
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 0);
|
||||
if (argc() < 2) {
|
||||
killme();
|
||||
}
|
||||
|
||||
if(! in_array($params['direction'],['asc','desc'])) {
|
||||
if (observer_prohibited(true)) {
|
||||
killme();
|
||||
}
|
||||
|
||||
$channel = channelx_by_nick(argv(1));
|
||||
if (!$channel) {
|
||||
killme();
|
||||
}
|
||||
|
||||
$params['begin'] = $_REQUEST['date_begin'] ?? DBA::$dba->get_null_date();
|
||||
$params['end'] = $_REQUEST['date_end'] ?? '';
|
||||
$params['type'] = 'xml';
|
||||
$params['pages'] = ((!empty($_REQUEST['pages'])) ? intval($_REQUEST['pages']) : 0);
|
||||
$params['top'] = ((array_key_exists('top', $_REQUEST)) ? intval($_REQUEST['top']) : PConfig::Get($channel['channel_id'], 'system', 'channel_simple_feed', 1));
|
||||
$params['start'] = ((!empty($_REQUEST['start'])) ? intval($_REQUEST['start']) : 0);
|
||||
$params['records'] = ((!empty($_REQUEST['records'])) ? intval($_REQUEST['records']) : 10);
|
||||
$params['cat'] = ((!empty($_REQUEST['cat'])) ? escape_tags($_REQUEST['cat']) : '');
|
||||
$params['compat'] = ((!empty($_REQUEST['compat'])) ? intval($_REQUEST['compat']) : 0);
|
||||
$params['direction'] = ((!empty($_REQUEST['direction'])) ? dbesc($_REQUEST['direction']) : 'desc');
|
||||
|
||||
if (!in_array($params['direction'], ['asc', 'desc'])) {
|
||||
$params['direction'] = 'desc';
|
||||
}
|
||||
|
||||
if(argc() > 1) {
|
||||
logger('public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
|
||||
|
||||
if(observer_prohibited(true)) {
|
||||
killme();
|
||||
}
|
||||
echo get_public_feed($channel, $params);
|
||||
|
||||
killme();
|
||||
|
||||
$channel = channelx_by_nick(argv(1));
|
||||
if(! $channel) {
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
logger('public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
|
||||
|
||||
echo get_public_feed($channel,$params);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,39 +11,42 @@ require_once('include/photos.php');
|
||||
class File_upload extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
logger('file upload: ' . print_r($_REQUEST,true));
|
||||
logger('file upload: ' . print_r($_POST,true));
|
||||
logger('file upload: ' . print_r($_FILES,true));
|
||||
|
||||
$channel = (($_REQUEST['channick']) ? channelx_by_nick($_REQUEST['channick']) : null);
|
||||
$channel = (($_POST['channick']) ? channelx_by_nick($_POST['channick']) : null);
|
||||
|
||||
if(! $channel) {
|
||||
if (!$channel) {
|
||||
logger('channel not found');
|
||||
killme();
|
||||
is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
|
||||
}
|
||||
|
||||
$_REQUEST['source'] = 'file_upload';
|
||||
$_POST['source'] = 'file_upload';
|
||||
|
||||
if($channel['channel_id'] != local_channel()) {
|
||||
$_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']);
|
||||
$_REQUEST['group_allow'] = expand_acl($channel['channel_allow_gid']);
|
||||
$_REQUEST['contact_deny'] = expand_acl($channel['channel_deny_cid']);
|
||||
$_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']);
|
||||
$_POST['contact_allow'] = expand_acl($channel['channel_allow_cid']);
|
||||
$_POST['group_allow'] = expand_acl($channel['channel_allow_gid']);
|
||||
$_POST['contact_deny'] = expand_acl($channel['channel_deny_cid']);
|
||||
$_POST['group_deny'] = expand_acl($channel['channel_deny_gid']);
|
||||
}
|
||||
|
||||
$_REQUEST['allow_cid'] = ((isset($_REQUEST['contact_allow'])) ? perms2str($_REQUEST['contact_allow']) : '');
|
||||
$_REQUEST['allow_gid'] = ((isset($_REQUEST['group_allow'])) ? perms2str($_REQUEST['group_allow']) : '');
|
||||
$_REQUEST['deny_cid'] = ((isset($_REQUEST['contact_deny'])) ? perms2str($_REQUEST['contact_deny']) : '');
|
||||
$_REQUEST['deny_gid'] = ((isset($_REQUEST['group_deny'])) ? perms2str($_REQUEST['group_deny']) : '');
|
||||
$_POST['allow_cid'] = ((isset($_POST['contact_allow'])) ? perms2str($_POST['contact_allow']) : '');
|
||||
$_POST['allow_gid'] = ((isset($_POST['group_allow'])) ? perms2str($_POST['group_allow']) : '');
|
||||
$_POST['deny_cid'] = ((isset($_POST['contact_deny'])) ? perms2str($_POST['contact_deny']) : '');
|
||||
$_POST['deny_gid'] = ((isset($_POST['group_deny'])) ? perms2str($_POST['group_deny']) : '');
|
||||
|
||||
if(isset($_REQUEST['filename']) && strlen($_REQUEST['filename'])) {
|
||||
$r = attach_mkdir($channel, get_observer_hash(), $_REQUEST);
|
||||
if($r['success']) {
|
||||
$hash = $r['data']['hash'];
|
||||
$sync = attach_export_data($channel,$hash);
|
||||
if($sync) {
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
}
|
||||
goaway(z_root() . '/' . $_REQUEST['return_url']);
|
||||
if(isset($_POST['filename']) && strlen($_POST['filename'])) {
|
||||
$r = attach_mkdir($channel, get_observer_hash(), $_POST);
|
||||
|
||||
if (!$r['success']) {
|
||||
notice($r['message'] . EOL);
|
||||
is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
|
||||
}
|
||||
|
||||
$hash = $r['data']['hash'];
|
||||
$sync = attach_export_data($channel,$hash);
|
||||
if ($sync) {
|
||||
Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -90,19 +93,19 @@ class File_upload extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$r = attach_store($channel, get_observer_hash(), '', $_REQUEST);
|
||||
if($r['success']) {
|
||||
$sync = attach_export_data($channel,$r['data']['hash']);
|
||||
if($sync)
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
$r = attach_store($channel, get_observer_hash(), '', $_POST);
|
||||
if (!$r['success']) {
|
||||
notice($r['message'] . EOL);
|
||||
is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
|
||||
}
|
||||
|
||||
$sync = attach_export_data($channel,$r['data']['hash']);
|
||||
if ($sync) {
|
||||
Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
|
||||
}
|
||||
}
|
||||
|
||||
if(is_ajax())
|
||||
killme();
|
||||
|
||||
goaway(z_root() . '/' . $_REQUEST['return_url']);
|
||||
is_ajax() ? killme() : goaway(z_root() . '/' . $_POST['return_url']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,14 @@ class Follow extends Controller {
|
||||
}
|
||||
|
||||
$uid = local_channel();
|
||||
$url = notags(punify(trim($_REQUEST['url'])));
|
||||
$url = notags(trim($_REQUEST['url']));
|
||||
|
||||
$parsed = parse_url($url);
|
||||
if (isset($parsed['host'])) {
|
||||
$parsed['host'] = punify($parsed['host']);
|
||||
$url = unparse_url($parsed);
|
||||
}
|
||||
|
||||
$return_url = $_SESSION['return_url'];
|
||||
$interactive = $_REQUEST['interactive'] ?? 1;
|
||||
$channel = App::get_channel();
|
||||
|
||||
@@ -30,7 +30,7 @@ class Help extends \Zotlabs\Web\Controller {
|
||||
$this->determine_help_language();
|
||||
|
||||
if (empty($_REQUEST['search']) && argc() === 1) {
|
||||
goaway("/help/about/about");
|
||||
goaway("/help/about");
|
||||
killme();
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class Help extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
|
||||
if(argc() > 2 && argv(argc()-2) === 'assets') {
|
||||
if(argc() > 2 && argv(argc()-2) === 'pic') {
|
||||
$path = '';
|
||||
for($x = 1; $x < argc(); $x ++) {
|
||||
if(strlen($path))
|
||||
|
||||
@@ -24,9 +24,13 @@ class Home extends Controller {
|
||||
$key = Config::Get('system', 'prvkey');
|
||||
$ret = json_encode(Libzot::site_info());
|
||||
|
||||
$headers = ['Content-Type' => 'application/x-zot+json', 'Digest' => HTTPSig::generate_digest_header($ret)];
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$h = HTTPSig::create_sig($headers, $key, z_root());
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'Digest' => HTTPSig::generate_digest_header($ret),
|
||||
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T')
|
||||
];
|
||||
|
||||
$h = HTTPSig::create_sig($headers, $key, z_root());
|
||||
HTTPSig::set_headers($h);
|
||||
|
||||
echo $ret;
|
||||
@@ -68,9 +72,9 @@ class Home extends Controller {
|
||||
|
||||
$o = '';
|
||||
|
||||
if (x($_SESSION, 'theme'))
|
||||
if (isset($_SESSION['theme']))
|
||||
unset($_SESSION['theme']);
|
||||
if (x($_SESSION, 'mobile_theme'))
|
||||
if (isset($_SESSION['mobile_theme']))
|
||||
unset($_SESSION['mobile_theme']);
|
||||
|
||||
$splash = ((argc() > 1 && argv(1) === 'splash') ? true : false);
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Widget\Messages;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Hq extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -50,14 +51,18 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
// select the target item with a bias to our own item
|
||||
$sql_order = ((local_channel() > $sys['channel_id']) ? 'DESC' : 'ASC');
|
||||
|
||||
$r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where uid in (%d, %d) and $identifier = '%s' order by uid $sql_order limit 2",
|
||||
$r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where uid in (%d, %d) and $identifier = '%s' order by uid $sql_order limit 2",
|
||||
intval(local_channel()),
|
||||
intval($sys['channel_id']),
|
||||
dbesc($item_hash)
|
||||
);
|
||||
|
||||
|
||||
if($r) {
|
||||
$target_item = $r[0];
|
||||
|
||||
call_hooks('item_custom_display', $target_item);
|
||||
|
||||
if (intval($target_item['uid']) === intval($sys['channel_id'])) {
|
||||
$sys_item = true;
|
||||
}
|
||||
@@ -86,7 +91,7 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
'default_location' => $channel['channel_location'],
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
|
||||
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'member/permissions'),
|
||||
'permissions' => $channel_acl,
|
||||
'bang' => '',
|
||||
'visitor' => true,
|
||||
@@ -129,7 +134,7 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
'$nouveau' => '0',
|
||||
'$wall' => '0',
|
||||
'$page' => '1',
|
||||
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
|
||||
'$list' => ((!empty($_REQUEST['list'])) ? intval($_REQUEST['list']) : 0),
|
||||
'$search' => '',
|
||||
'$xchan' => '',
|
||||
'$order' => '',
|
||||
@@ -145,7 +150,6 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($load && $target_item) {
|
||||
|
||||
if (!$sys_item) {
|
||||
$r = q("SELECT item.id AS item_id FROM item
|
||||
WHERE uid = %d
|
||||
@@ -199,11 +203,8 @@ class Hq extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($r) {
|
||||
$items = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE parent = '%s' $item_normal $sql_extra",
|
||||
dbesc($r[0]['item_id'])
|
||||
);
|
||||
$thr_parents = get_recursive_thr_parents($target_item);
|
||||
$items = items_by_parent_ids($r, $thr_parents);
|
||||
|
||||
xchan_query($items,true,(($sys_item) ? local_channel() : 0));
|
||||
$items = fetch_post_tags($items,true);
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace Zotlabs\Module;
|
||||
*
|
||||
* Controller for responding to x-zot: protocol requests
|
||||
* x-zot:_jkfRG85nJ-714zn-LW_VbTFW8jSjGAhAydOcJzHxqHkvEHWG2E0RbA_pbch-h4R63RG1YJZifaNzgccoLa3MQ/453c1678-1a79-4af7-ab65-6b012f6cab77
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
@@ -104,7 +104,7 @@ class Id extends Controller {
|
||||
$headers['Content-Type'] = 'application/x-zot+json' ;
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
|
||||
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $ret;
|
||||
|
||||
@@ -7,6 +7,7 @@ require_once('include/import.php');
|
||||
require_once('include/perm_upgrade.php');
|
||||
|
||||
use App;
|
||||
use DBA;
|
||||
use URLify;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\Config;
|
||||
@@ -331,7 +332,7 @@ class Import extends Controller {
|
||||
else {
|
||||
$photos = import_xchan_photo($xchan['xchan_photo_l'], $xchan['xchan_hash']);
|
||||
if ($photos[4])
|
||||
$photodate = NULL_DATE;
|
||||
$photodate = DBA::$dba->get_null_date();
|
||||
else
|
||||
$photodate = $xchan['xchan_photo_date'];
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use DBA;
|
||||
use URLify;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\IConfig;
|
||||
@@ -17,6 +18,7 @@ use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Lib\ThreadListener;
|
||||
use Zotlabs\Access\PermissionRoles;
|
||||
use Zotlabs\Lib\ObjCache;
|
||||
|
||||
require_once('include/crypto.php');
|
||||
require_once('include/items.php');
|
||||
@@ -53,12 +55,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 +80,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 +109,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 +123,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 +133,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 +162,44 @@ 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']) : $item_type !== ITEM_TYPE_POST);
|
||||
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -206,7 +210,7 @@ class Item extends Controller {
|
||||
}
|
||||
|
||||
|
||||
$expires = NULL_DATE;
|
||||
$expires = DBA::$dba->get_null_date();
|
||||
|
||||
$route = '';
|
||||
$parent_item = null;
|
||||
@@ -216,8 +220,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 +257,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 +280,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 +292,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 +311,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 +377,7 @@ class Item extends Controller {
|
||||
logger("mod_item: no channel.");
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'no channel']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -391,7 +395,7 @@ class Item extends Controller {
|
||||
logger("mod_item: no owner.");
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'no owner']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -425,17 +429,21 @@ class Item extends Controller {
|
||||
$view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'view_stream');
|
||||
$comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'post_comments');
|
||||
|
||||
$public_policy = ((x($_REQUEST, 'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy, true));
|
||||
if ($webpage)
|
||||
$public_policy = '';
|
||||
if ($public_policy)
|
||||
$public_policy = '';
|
||||
|
||||
if (intval($item_type) === ITEM_TYPE_POST) {
|
||||
$public_policy = ((!empty($_POST['public_policy'])) ? escape_tags($_POST['public_policy']) : map_scope($view_policy, true));
|
||||
}
|
||||
|
||||
if ($public_policy) {
|
||||
$private = 1;
|
||||
}
|
||||
|
||||
if ($orig_post) {
|
||||
$private = 0;
|
||||
// webpages are allowed to change ACLs after the fact. Normal conversation items aren't.
|
||||
if ($webpage) {
|
||||
$acl->set_from_array($_REQUEST);
|
||||
// Normal conversation items are not allowed to change ACL.
|
||||
if (intval($item_type) !== ITEM_TYPE_POST) {
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
else {
|
||||
$acl->set($orig_post);
|
||||
@@ -451,9 +459,9 @@ class Item extends Controller {
|
||||
$coord = $orig_post['coord'];
|
||||
$verb = $orig_post['verb'];
|
||||
$app = $orig_post['app'];
|
||||
$title = escape_tags(trim($_REQUEST['title']));
|
||||
$summary = escape_tags(trim($_REQUEST['summary']));
|
||||
$body = trim($_REQUEST['body']);
|
||||
$title = escape_tags(trim($_POST['title']));
|
||||
$summary = escape_tags(trim($_POST['summary']));
|
||||
$body = trim($_POST['body']);
|
||||
$item_flags = $orig_post['item_flags'];
|
||||
$item_origin = $orig_post['item_origin'];
|
||||
$item_unseen = $orig_post['item_unseen'];
|
||||
@@ -491,11 +499,11 @@ class Item extends Controller {
|
||||
}
|
||||
else {
|
||||
if (!$walltowall) {
|
||||
if ((array_key_exists('contact_allow', $_REQUEST))
|
||||
|| (array_key_exists('group_allow', $_REQUEST))
|
||||
|| (array_key_exists('contact_deny', $_REQUEST))
|
||||
|| (array_key_exists('group_deny', $_REQUEST))) {
|
||||
$acl->set_from_array($_REQUEST);
|
||||
if ((array_key_exists('contact_allow', $_POST))
|
||||
|| (array_key_exists('group_allow', $_POST))
|
||||
|| (array_key_exists('contact_deny', $_POST))
|
||||
|| (array_key_exists('group_deny', $_POST))) {
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
elseif (!$api_source) {
|
||||
|
||||
@@ -510,16 +518,16 @@ class Item extends Controller {
|
||||
}
|
||||
|
||||
|
||||
$location = ((isset($_REQUEST['location'])) ? notags(trim($_REQUEST['location'])) : '');
|
||||
$coord = ((isset($_REQUEST['coord'])) ? notags(trim($_REQUEST['coord'])) : '');
|
||||
$verb = ((isset($_REQUEST['verb'])) ? notags(trim($_REQUEST['verb'])) : '');
|
||||
$title = ((isset($_REQUEST['title'])) ? escape_tags(trim($_REQUEST['title'])) : '');
|
||||
$summary = ((isset($_REQUEST['summary'])) ? escape_tags(trim($_REQUEST['summary'])) : '');
|
||||
$body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : '');
|
||||
$body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : '');
|
||||
$location = ((isset($_POST['location'])) ? notags(trim($_POST['location'])) : '');
|
||||
$coord = ((isset($_POST['coord'])) ? notags(trim($_POST['coord'])) : '');
|
||||
$verb = ((isset($_POST['verb'])) ? notags(trim($_POST['verb'])) : '');
|
||||
$title = ((isset($_POST['title'])) ? escape_tags(trim($_POST['title'])) : '');
|
||||
$summary = ((isset($_POST['summary'])) ? escape_tags(trim($_POST['summary'])) : '');
|
||||
$body = ((isset($_POST['body'])) ? trim($_POST['body']) : '');
|
||||
$body .= ((isset($_POST['attachment'])) ? trim($_POST['attachment']) : '');
|
||||
$postopts = '';
|
||||
|
||||
$allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
|
||||
$allow_empty = ((array_key_exists('allow_empty', $_POST)) ? intval($_POST['allow_empty']) : 0);
|
||||
|
||||
$private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy)));
|
||||
|
||||
@@ -530,7 +538,7 @@ class Item extends Controller {
|
||||
$private = intval($parent_item['item_private']);
|
||||
$public_policy = $parent_item['public_policy'];
|
||||
$owner_hash = $parent_item['owner_xchan'];
|
||||
$webpage = $parent_item['item_type'];
|
||||
$item_type = $parent_item['item_type'];
|
||||
}
|
||||
|
||||
|
||||
@@ -541,7 +549,7 @@ class Item extends Controller {
|
||||
info(t('Empty post discarded.') . EOL);
|
||||
if ($api_source)
|
||||
return (['success' => false, 'message' => 'no content']);
|
||||
if (x($_REQUEST, 'return'))
|
||||
if (!empty($_POST['return']))
|
||||
goaway(z_root() . "/" . $return_path);
|
||||
killme();
|
||||
}
|
||||
@@ -549,15 +557,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;
|
||||
$expires = DBA::$dba->get_null_date();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$mimetype = ((isset($_REQUEST['mimetype'])) ? notags(trim($_REQUEST['mimetype'])) : '');
|
||||
$mimetype = ((isset($_POST['mimetype'])) ? notags(trim($_POST['mimetype'])) : '');
|
||||
|
||||
if (!$mimetype)
|
||||
$mimetype = 'text/bbcode';
|
||||
@@ -591,7 +599,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 = '';
|
||||
@@ -750,7 +758,7 @@ class Item extends Controller {
|
||||
$cats = explode(',', $categories);
|
||||
foreach ($cats as $cat) {
|
||||
|
||||
$catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat));
|
||||
$catlink = channel_url($channel) . '?cat=' . urlencode(trim($cat));
|
||||
|
||||
$post_tags[] = [
|
||||
'uid' => $profile_uid,
|
||||
@@ -790,23 +798,21 @@ 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);
|
||||
$comments_closed = (($nocomment) ? $comments_closed : NULL_DATE);
|
||||
$comments_closed = (($nocomment) ? $comments_closed : DBA::$dba->get_null_date());
|
||||
|
||||
// determine if this is a wall post
|
||||
|
||||
if (in_array($item_type, [ITEM_TYPE_POST, ITEM_TYPE_CARD, ITEM_TYPE_ARTICLE])) {
|
||||
$item_wall = 1;
|
||||
}
|
||||
|
||||
if ($parent) {
|
||||
$item_wall = $parent_item['item_wall'];
|
||||
}
|
||||
else {
|
||||
if (!$webpage) {
|
||||
$item_wall = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($moderated) {
|
||||
$item_blocked = ITEM_MODERATED;
|
||||
@@ -847,10 +853,10 @@ class Item extends Controller {
|
||||
if ($is_poll) {
|
||||
$poll = [
|
||||
'question' => $body,
|
||||
'answers' => $_REQUEST['poll_answers'],
|
||||
'multiple_answers' => $_REQUEST['poll_multiple_answers'],
|
||||
'expire_value' => $_REQUEST['poll_expire_value'],
|
||||
'expire_unit' => $_REQUEST['poll_expire_unit']
|
||||
'answers' => $_POST['poll_answers'],
|
||||
'multiple_answers' => $_POST['poll_multiple_answers'],
|
||||
'expire_value' => $_POST['poll_expire_value'],
|
||||
'expire_unit' => $_POST['poll_expire_unit']
|
||||
];
|
||||
$obj = $this->extract_poll_data($poll, ['item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny]);
|
||||
}
|
||||
@@ -870,7 +876,7 @@ class Item extends Controller {
|
||||
|
||||
if ($obj['endTime']) {
|
||||
$d = datetime_convert('UTC','UTC', $obj['endTime']);
|
||||
if ($d > NULL_DATE) {
|
||||
if ($d > DBA::$dba->get_null_date()) {
|
||||
$comments_closed = $d;
|
||||
}
|
||||
}
|
||||
@@ -929,7 +935,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);
|
||||
@@ -1008,14 +1014,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();
|
||||
}
|
||||
@@ -1024,8 +1030,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) {
|
||||
@@ -1038,23 +1044,16 @@ class Item extends Controller {
|
||||
|
||||
$x = item_store_update($datarray, $execflag);
|
||||
|
||||
if ($x['success']) {
|
||||
if ($x['success'] && intval($item_type) === ITEM_TYPE_POST) {
|
||||
$item = [$x['item']];
|
||||
xchan_query($item);
|
||||
$item = fetch_post_tags($item);
|
||||
$encoded_item = Activity::build_packet(Activity::encode_activity($item[0]), $channel, false);
|
||||
ObjCache::Set($item[0]['mid'], $encoded_item);
|
||||
|
||||
$this->add_listeners($datarray);
|
||||
}
|
||||
|
||||
/* sync this is done in item_store_update()
|
||||
if (!$parent) {
|
||||
$r = q("select * from item where id = %d",
|
||||
intval($post_id)
|
||||
);
|
||||
if ($r) {
|
||||
xchan_query($r);
|
||||
$sync_item = fetch_post_tags($r);
|
||||
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (!$nopush) {
|
||||
Master::Summon(['Notifier', 'edit_post', $post_id]);
|
||||
if (intval($x['approval_id'])) {
|
||||
@@ -1065,7 +1064,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') {
|
||||
@@ -1077,9 +1076,17 @@ class Item extends Controller {
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
$post = item_store($datarray, $execflag);
|
||||
|
||||
if ($post['success']) {
|
||||
if ($post['success'] && intval($item_type) === ITEM_TYPE_POST) {
|
||||
$item = [$post['item']];
|
||||
xchan_query($item);
|
||||
// TODO: fetch_post_tags() will add term and iconfig twice if called twice and it looks like they are already added here
|
||||
//$item = fetch_post_tags($item);
|
||||
$encoded_item = Activity::build_packet(Activity::encode_activity($item[0]), $channel, false);
|
||||
ObjCache::Set($item[0]['mid'], $encoded_item);
|
||||
|
||||
$this->add_listeners($datarray);
|
||||
}
|
||||
|
||||
@@ -1159,19 +1166,6 @@ class Item extends Controller {
|
||||
killme();
|
||||
}
|
||||
|
||||
/* sync this is done in item_store_update()
|
||||
if ($parent || $datarray['item_private'] == 1) {
|
||||
$r = q("select * from item where id = %d",
|
||||
intval($post_id)
|
||||
);
|
||||
if ($r) {
|
||||
xchan_query($r);
|
||||
$sync_item = fetch_post_tags($r);
|
||||
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
$datarray['id'] = $post_id;
|
||||
$datarray['llink'] = z_root() . '/display/' . $datarray['uuid'];
|
||||
|
||||
@@ -1210,19 +1204,15 @@ class Item extends Controller {
|
||||
if ($mode === 'channel')
|
||||
profile_load($channel['channel_address']);
|
||||
|
||||
$item[] = $datarray;
|
||||
$item[0]['owner'] = $owner_xchan;
|
||||
$item[0]['author'] = $observer;
|
||||
$item[0]['attach'] = $datarray['attach'];
|
||||
|
||||
$json = [
|
||||
'success' => 1,
|
||||
'id' => $post_id,
|
||||
'thr_parent_id' => $thr_parent_id,
|
||||
'html' => conversation($item, $mode, true, 'r_preview'),
|
||||
];
|
||||
|
||||
if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload']))
|
||||
$json['reload'] = z_root() . '/' . $_REQUEST['jsreload'];
|
||||
if (!empty($_POST['jsreload']))
|
||||
$json['reload'] = z_root() . '/' . $_POST['jsreload'];
|
||||
|
||||
logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
|
||||
|
||||
|
||||
@@ -65,8 +65,22 @@ class Lang extends Controller {
|
||||
}
|
||||
|
||||
nav_set_selected('Language');
|
||||
return lang_selector();
|
||||
return $this->lang_selector();
|
||||
|
||||
}
|
||||
|
||||
private function lang_selector(): string
|
||||
{
|
||||
$lang_options = language_list();
|
||||
array_unshift($lang_options, t('default'));
|
||||
|
||||
$tpl = get_markup_template('lang_selector.tpl');
|
||||
|
||||
return replace_macros($tpl, [
|
||||
'$title' => t('Select an alternate language'),
|
||||
'$langs' => array($lang_options, App::$language),
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ class Like extends Controller {
|
||||
'like' => 'Like',
|
||||
'dislike' => 'Dislike',
|
||||
'announce' => ACTIVITY_SHARE,
|
||||
'attendyes' => 'Accept',
|
||||
'attendno' => 'Reject',
|
||||
'attendmaybe' => 'TentativeAccept'
|
||||
'accept' => 'Accept',
|
||||
'reject' => 'Reject',
|
||||
'tentativeaccept' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
// unlike (etc.) reactions are an undo of positive reactions, rather than a negative action.
|
||||
@@ -52,43 +52,31 @@ class Like extends Controller {
|
||||
profile_load($parts[0]);
|
||||
}
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
if ($page_mode === 'list') {
|
||||
$item_normal = item_normal();
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id FROM item
|
||||
WHERE uid = %d $item_normal
|
||||
AND parent = %d",
|
||||
intval($arr['item']['uid']),
|
||||
intval($arr['item']['parent'])
|
||||
);
|
||||
|
||||
xchan_query($items, true);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$items = conv_sort($items, 'commented');
|
||||
}
|
||||
else {
|
||||
$activities = q("SELECT item.*, item.id AS item_id FROM item
|
||||
WHERE uid = %d $item_normal
|
||||
AND thr_parent = '%s'
|
||||
AND verb IN ('%s', '%s', '%s', '%s', '%s', '%s', 'Accept', 'Reject', 'TentativeAccept')",
|
||||
intval($arr['item']['uid']),
|
||||
dbesc($arr['item']['mid']),
|
||||
dbesc('Like'),
|
||||
dbesc('Dislike'),
|
||||
dbesc(ACTIVITY_SHARE),
|
||||
dbesc(ACTIVITY_ATTEND),
|
||||
dbesc(ACTIVITY_ATTENDNO),
|
||||
dbesc(ACTIVITY_ATTENDMAYBE)
|
||||
);
|
||||
xchan_query($activities, true);
|
||||
$items = array_merge([$arr['item']], $activities);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$item = item_by_item_id($arr['item']['id'], $arr['item']['parent'], type: $arr['item']['item_type']);
|
||||
xchan_query($item, true);
|
||||
$item = fetch_post_tags($item, true);
|
||||
}
|
||||
|
||||
$ret = [
|
||||
'success' => 1,
|
||||
'orig_id' => $arr['orig_item_id'], //this is required for pubstream items where $item_id != $item['id']
|
||||
'id' => $arr['item']['id'],
|
||||
'html' => conversation($items, $conv_mode, true, $page_mode),
|
||||
'html' => conversation($item, $conv_mode, true, $page_mode),
|
||||
];
|
||||
|
||||
// mod photos
|
||||
@@ -139,7 +127,7 @@ class Like extends Controller {
|
||||
$extended_like = false;
|
||||
$object = $target = null;
|
||||
$post_type = EMPTY_STR;
|
||||
$obj_type = EMPTY_STR;
|
||||
$obj_type = EMPTY_STR;
|
||||
|
||||
if (argc() == 3) {
|
||||
|
||||
@@ -317,8 +305,6 @@ class Like extends Controller {
|
||||
// parent, copy that as well.
|
||||
|
||||
if ($r) {
|
||||
$obj_type = $r[0]['obj_type'];
|
||||
|
||||
if ($r[0]['uid'] === $sys_channel['channel_id'] && local_channel()) {
|
||||
$r = [copy_of_pubitem(App::get_channel(), $r[0]['mid'])];
|
||||
}
|
||||
@@ -334,6 +320,8 @@ class Like extends Controller {
|
||||
$item = $r[0];
|
||||
$owner_uid = $r[0]['uid'];
|
||||
$owner_aid = $r[0]['aid'];
|
||||
$obj_type = $r[0]['obj_type'];
|
||||
$item_type = $r[0]['item_type'];
|
||||
|
||||
if ((array_key_exists('owner', $item)) && intval($item['owner']['abook_self']))
|
||||
$can_comment = perm_is_allowed($item['uid'], $observer['xchan_hash'], 'post_comments');
|
||||
@@ -374,7 +362,7 @@ class Like extends Controller {
|
||||
$multi_undo = true;
|
||||
}
|
||||
|
||||
$item_normal = item_normal();
|
||||
$item_normal = item_normal(type: $item_type);
|
||||
|
||||
$r = q("SELECT id, parent, uid, verb FROM item WHERE verb in ( $verbs ) $item_normal
|
||||
AND author_xchan = '%s' AND thr_parent = '%s' and uid = %d ",
|
||||
@@ -445,7 +433,7 @@ class Like extends Controller {
|
||||
$arr['item_wall'] = 1;
|
||||
}
|
||||
else {
|
||||
switch ($item['object_type']) {
|
||||
switch ($item['obj_type']) {
|
||||
case 'Image':
|
||||
$post_type = t('image');
|
||||
break;
|
||||
@@ -486,11 +474,11 @@ class Like extends Controller {
|
||||
$bodyverb = t('%1$s likes %2$s\'s %3$s');
|
||||
if ($verb === 'dislike')
|
||||
$bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
|
||||
if ($verb === 'attendyes')
|
||||
if ($verb === 'accept')
|
||||
$bodyverb = t('%1$s is attending %2$s\'s %3$s');
|
||||
if ($verb === 'attendno')
|
||||
if ($verb === 'reject')
|
||||
$bodyverb = t('%1$s is not attending %2$s\'s %3$s');
|
||||
if ($verb === 'attendmaybe')
|
||||
if ($verb === 'tentativeaccept')
|
||||
$bodyverb = t('%1$s may attend %2$s\'s %3$s');
|
||||
|
||||
if (!isset($bodyverb))
|
||||
@@ -573,7 +561,7 @@ class Like extends Controller {
|
||||
|
||||
call_hooks('post_local_end', $arr);
|
||||
|
||||
if ($is_rsvp && in_array($verb, ['attendyes', 'attendmaybe'])) {
|
||||
if ($is_rsvp && in_array($verb, ['accept', 'tentativeaccept'])) {
|
||||
event_addtocal($item_id, local_channel());
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ class Lockview extends Controller {
|
||||
// as unknown specific recipients. The sender will have the visibility list and will fall through to the
|
||||
// next section.
|
||||
|
||||
echo '<div class="dropdown-item-text">' . translate_scope((!$item['public_policy']) ? 'specific' : $item['public_policy']) . '</div>';
|
||||
echo '<div class="dropdown-item-text">' . escape_tags(translate_scope((!$item['public_policy']) ? 'specific' : $item['public_policy'])) . '</div>';
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -232,25 +232,17 @@ class Lockview extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$access_list_header = '<div class="dropdown-header text-uppercase h6">' . t('Access') . '</div>';
|
||||
$guest_access_list_header = '<div class="dropdown-header text-uppercase h6">' . t('Guest access') . '</div>';
|
||||
$ocap_access_list_header = '<div class="dropdown-header text-uppercase h6">' . t('OCAP access') . '</div>';
|
||||
$divider = '<div class="dropdown-divider"></div>';
|
||||
$str = '';
|
||||
$tpl = get_markup_template('access_dropdown.tpl');
|
||||
|
||||
if ($access_list) {
|
||||
$str .= $access_list_header . implode($access_list);
|
||||
}
|
||||
echo replace_macros($tpl, [
|
||||
'$access_header' => t('Access'),
|
||||
'$guest_access_header' => t('Guest access'),
|
||||
'$ocap_access_header' => t('OCAP access'),
|
||||
|
||||
if ($guest_access_list) {
|
||||
$str .= $divider . $guest_access_list_header . implode($guest_access_list);
|
||||
}
|
||||
|
||||
if ($ocap_access_list) {
|
||||
$str .= $divider . $ocap_access_list_header . implode($ocap_access_list);
|
||||
}
|
||||
|
||||
echo $str;
|
||||
'$access_list' => $access_list ? implode($access_list) : '',
|
||||
'$guest_access_list' => $guest_access_list ? implode($guest_access_list) : '',
|
||||
'$ocap_access_list' => $ocap_access_list ? implode($ocap_access_list) : '',
|
||||
]);
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
@@ -5,10 +5,17 @@ namespace Zotlabs\Module;
|
||||
class Login extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
if(local_channel())
|
||||
if (local_channel()) {
|
||||
goaway(z_root());
|
||||
if(remote_channel() && $_SESSION['atoken'])
|
||||
}
|
||||
|
||||
if (remote_channel() && $_SESSION['atoken']) {
|
||||
goaway(z_root());
|
||||
}
|
||||
|
||||
if (!empty($_GET['retry'])) {
|
||||
notice( t('Login failed.') . EOL );
|
||||
}
|
||||
|
||||
$o = '<div class="generic-content-wrapper">';
|
||||
$o .= '<div class="section-title-wrapper">';
|
||||
|
||||
@@ -6,6 +6,8 @@ use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\SConfig;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use HttpSignature\HttpMessageSigner;
|
||||
|
||||
class Magic extends Controller {
|
||||
|
||||
@@ -41,11 +43,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');
|
||||
|
||||
@@ -105,26 +103,65 @@ class Magic extends Controller {
|
||||
$dest = strip_zids($dest);
|
||||
$dest = strip_query_param($dest,'f');
|
||||
|
||||
// We now post to the OWA endpoint. This improves security by providing a signed digest
|
||||
// try RFC9421 first
|
||||
|
||||
$data = json_encode([ 'OpenWebAuth' => random_string() ]);
|
||||
$request = new Request(
|
||||
'GET',
|
||||
$owapath,
|
||||
[
|
||||
'Host' => $parsed['host'],
|
||||
'Date' => gmdate('D, d M Y H:i:s T'),
|
||||
'Accept' => 'application/x-zot+json',
|
||||
'X-Open-Web-Auth' => random_string(),
|
||||
],
|
||||
);
|
||||
|
||||
$headers = [];
|
||||
$headers['Accept'] = 'application/x-zot+json' ;
|
||||
$headers['Content-Type'] = 'application/x-zot+json' ;
|
||||
$headers['X-Open-Web-Auth'] = random_string();
|
||||
$headers['Host'] = $parsed['host'];
|
||||
$headers['(request-target)'] = 'get /owa';
|
||||
$signer = new HttpMessageSigner();
|
||||
|
||||
$signer->setPrivateKey($channel['channel_prvkey']);
|
||||
$signer->setAlgorithm('rsa-v1_5-sha256');
|
||||
$signer->setKeyId(channel_url($channel));
|
||||
$signer->setCreated(time());
|
||||
$signer->setExpires(time() + 3600);
|
||||
|
||||
$coveredFields = '("@method" "@target-uri" "host" "date" "accept" "x-open-web-auth")';
|
||||
$request = $signer->signRequest($coveredFields, $request);
|
||||
$signedHeaders = $signer->getHeaders($request);
|
||||
|
||||
$curlHeaders = [];
|
||||
foreach ($signedHeaders as $key => $value) {
|
||||
$curlHeaders[] = $key . ': ' . $value;
|
||||
}
|
||||
|
||||
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
|
||||
$redirects = 0;
|
||||
$x = z_fetch_url($owapath, false, $redirects, ['headers' => $curlHeaders]);
|
||||
logger('owa RFC9421 fetch returned: ' . print_r($x,true),LOGGER_DATA);
|
||||
|
||||
$x = z_fetch_url($owapath, false, $redirects, ['headers' => $headers]);
|
||||
$rfc9421 = false;
|
||||
|
||||
logger('owa fetch returned: ' . print_r($x,true),LOGGER_DATA);
|
||||
if ($x['success']) {
|
||||
$rfc9421_result = json_decode($x['body'], true);
|
||||
$rfc9421 = $rfc9421_result['success'];
|
||||
}
|
||||
|
||||
if (!$rfc9421 || ($x['return_code'] >= 400 && $x['return_code'] != 404)) {
|
||||
$headers = [];
|
||||
$headers['Accept'] = 'application/x-zot+json' ;
|
||||
$headers['Content-Type'] = 'application/x-zot+json' ;
|
||||
$headers['X-Open-Web-Auth'] = random_string();
|
||||
$headers['Host'] = $parsed['host'];
|
||||
$headers['(request-target)'] = 'get /owa';
|
||||
|
||||
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
|
||||
$redirects = 0;
|
||||
|
||||
$x = z_fetch_url($owapath, false, $redirects, ['headers' => $headers]);
|
||||
logger('owa fetch returned: ' . print_r($x,true),LOGGER_DATA);
|
||||
}
|
||||
|
||||
if ($x['success']) {
|
||||
$j = json_decode($x['body'],true);
|
||||
|
||||
if ($j['success'] && $j['encrypted_token']) {
|
||||
// decrypt the token using our private key
|
||||
$token = '';
|
||||
@@ -142,12 +179,13 @@ class Magic extends Controller {
|
||||
$o .= '<a href=' . $dest . '>' . $dest . '</a>';
|
||||
|
||||
echo $o;
|
||||
killme();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
killme();
|
||||
goaway($dest);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class Moderate extends \Zotlabs\Web\Controller {
|
||||
|
||||
$item['item_blocked'] = 0;
|
||||
item_update_parent_commented($item);
|
||||
notice( t('Item approved') . EOL);
|
||||
info(t('Item approved') . EOL);
|
||||
}
|
||||
elseif($action === 'drop') {
|
||||
// TODO: not implemented
|
||||
@@ -75,7 +75,7 @@ class Moderate extends \Zotlabs\Web\Controller {
|
||||
// Activity::send_rejection_activity(App::get_channel(), $item['author_xchan'], $item);
|
||||
|
||||
drop_item($post_id);
|
||||
notice( t('Item deleted') . EOL);
|
||||
info(t('Item deleted') . EOL);
|
||||
}
|
||||
|
||||
// refetch the item after changes have been made
|
||||
|
||||
@@ -70,17 +70,19 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
$dm = ((x($_REQUEST,'dm')) ? $_REQUEST['dm'] : 0);
|
||||
|
||||
|
||||
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
|
||||
$order = get_pconfig(local_channel(), 'mod_network', 'order', 'created');
|
||||
switch($order) {
|
||||
case 0:
|
||||
$order = 'comment';
|
||||
case 'commented':
|
||||
$ordering = 'commented';
|
||||
break;
|
||||
case 1:
|
||||
$order = 'post';
|
||||
case 'created':
|
||||
$ordering = 'created';
|
||||
break;
|
||||
case 2:
|
||||
case 'unthreaded':
|
||||
$nouveau = true;
|
||||
break;
|
||||
default:
|
||||
$ordering = 'created';
|
||||
}
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
@@ -92,7 +94,7 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($datequery)
|
||||
$order = 'post';
|
||||
$order = 'created';
|
||||
|
||||
|
||||
// filter by collection (e.g. group)
|
||||
@@ -133,7 +135,6 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
|
||||
$status_editor = '';
|
||||
|
||||
|
||||
if (Apps::system_app_installed(local_channel(), 'Affinity Tool')) {
|
||||
$affinity_locked = intval(get_pconfig(local_channel(), 'affinity', 'lock', 1));
|
||||
if ($affinity_locked) {
|
||||
@@ -142,8 +143,11 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
if(x($_GET, 'search') || $file || (!$pf && $cid) || $hashtags || $verb || $category || $conv || $unseen)
|
||||
if($search || $file || (!$pf && $cid) || $hashtags || $verb || $category || $conv || $unseen) {
|
||||
$nouveau = true;
|
||||
}
|
||||
|
||||
$dismiss_privacy_filter = array_intersect(['cid', 'star', 'conv', 'file', 'verb', 'cat', 'search'], array_keys($_GET));
|
||||
|
||||
$cid_r = [];
|
||||
|
||||
@@ -201,7 +205,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,15 +275,6 @@ 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)
|
||||
$sql_extra = " AND item.parent IN (SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal) AND item_unseen = 1 AND verb != 'Announce' $likes_sql ";
|
||||
}
|
||||
else {
|
||||
// This is for threaded view cid queries (e.g. if a forum is selected from the forum filter)
|
||||
$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) ";
|
||||
@@ -354,15 +349,15 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
// The name 'verb' is a holdover from the earlier XML
|
||||
// ActivityStreams specification.
|
||||
|
||||
if (substr($verb, 0, 1) === '.') {
|
||||
if (str_starts_with($verb, '.')) {
|
||||
$sql_verb = substr($verb, 1);
|
||||
$sql_extra .= sprintf(" AND item.obj_type like '%s' ",
|
||||
dbesc(protect_sprintf('%' . $sql_verb . '%'))
|
||||
$sql_extra .= sprintf(" AND item.obj_type = '%s' AND item.verb IN ('Create', 'Update', 'Invite') ",
|
||||
dbesc(protect_sprintf($sql_verb))
|
||||
);
|
||||
}
|
||||
else {
|
||||
$sql_extra .= sprintf(" AND item.verb like '%s' ",
|
||||
dbesc(protect_sprintf('%' . $verb . '%'))
|
||||
$sql_extra .= sprintf(" AND item.verb = '%s' ",
|
||||
dbesc(protect_sprintf($verb))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -371,30 +366,23 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
$sql_extra .= term_query('item', $file, TERM_FILE);
|
||||
}
|
||||
|
||||
if ($dm) {
|
||||
$sql_extra .= ' AND item_private = 2 ';
|
||||
if (!$dismiss_privacy_filter) {
|
||||
if ($dm) {
|
||||
$sql_extra .= ' AND item.item_private = 2 ';
|
||||
}
|
||||
else {
|
||||
$sql_extra .= ' AND item.item_private IN (0, 1) ';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$sql_extra .= ' AND item_private IN (0, 1) ';
|
||||
}
|
||||
|
||||
|
||||
if($conv) {
|
||||
$item_thread_top = '';
|
||||
$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
|
||||
|
||||
@@ -424,12 +412,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
|
||||
@@ -451,33 +439,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
|
||||
@@ -506,12 +484,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);
|
||||
|
||||
@@ -33,7 +33,7 @@ class New_channel extends \Zotlabs\Web\Controller {
|
||||
// first name
|
||||
if(strpos($x,' '))
|
||||
$test[] = legal_webbie(substr($x,0,strpos($x,' ')));
|
||||
if($test[0]) {
|
||||
if (!empty($test[0])) {
|
||||
// first name plus first initial of last
|
||||
$test[] = ((strpos($x,' ')) ? $test[0] . legal_webbie(trim(substr($x,strpos($x,' '),2))) : '');
|
||||
// first name plus random number
|
||||
@@ -69,7 +69,7 @@ class New_channel extends \Zotlabs\Web\Controller {
|
||||
// first name
|
||||
if(strpos($x,' '))
|
||||
$test[] = legal_webbie(substr($x,0,strpos($x,' ')));
|
||||
if($test[0]) {
|
||||
if (!empty($test[0])) {
|
||||
// first name plus first initial of last
|
||||
$test[] = ((strpos($x,' ')) ? $test[0] . legal_webbie(trim(substr($x,strpos($x,' '),2))) : '');
|
||||
// first name plus random number
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/contact_widgets.php');
|
||||
require_once('include/items.php');
|
||||
require_once("include/bbcode.php");
|
||||
require_once('include/security.php');
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/acl_selectors.php');
|
||||
require_once('include/permissions.php');
|
||||
|
||||
/**
|
||||
* @brief Channel Controller for broken OStatus implementations
|
||||
*
|
||||
*/
|
||||
class Ochannel extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$which = null;
|
||||
if(argc() > 1)
|
||||
$which = argv(1);
|
||||
if(! $which) {
|
||||
if(local_channel()) {
|
||||
$channel = \App::get_channel();
|
||||
if($channel && $channel['channel_address'])
|
||||
$which = $channel['channel_address'];
|
||||
}
|
||||
}
|
||||
if(! $which) {
|
||||
notice( t('You must be logged in to see this page.') . EOL );
|
||||
return;
|
||||
}
|
||||
|
||||
$profile = 0;
|
||||
$channel = \App::get_channel();
|
||||
|
||||
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
}
|
||||
|
||||
head_add_link( [
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/atom+xml',
|
||||
'href' => z_root() . '/ofeed/' . $which
|
||||
]);
|
||||
|
||||
|
||||
// Run profile_load() here to make sure the theme is set before
|
||||
// we start loading content
|
||||
|
||||
profile_load($which,$profile);
|
||||
}
|
||||
|
||||
function get($update = 0, $load = false) {
|
||||
|
||||
if(argc() < 2)
|
||||
return;
|
||||
|
||||
if($load)
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
|
||||
return '<script>window.location.href = "' . z_root() . '/' . str_replace('ochannel/','channel/',\App::$query_string) . '";</script>';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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'] ?? '';
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
/* Ofeed: Broken feed for software which requires broken feeds */
|
||||
|
||||
require_once('include/items.php');
|
||||
|
||||
class Ofeed extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$params = [];
|
||||
|
||||
$params['begin'] = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE);
|
||||
$params['end'] = ((x($_REQUEST,'date_end')) ? $_REQUEST['date_end'] : '');
|
||||
$params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
|
||||
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
|
||||
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
|
||||
$params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0);
|
||||
$params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 10);
|
||||
$params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
|
||||
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
|
||||
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 1);
|
||||
|
||||
if(! in_array($params['direction'],['asc','desc'])) {
|
||||
$params['direction'] = 'desc';
|
||||
}
|
||||
|
||||
if(argc() > 1) {
|
||||
|
||||
if(observer_prohibited(true)) {
|
||||
killme();
|
||||
}
|
||||
|
||||
$channel = channelx_by_nick(argv(1));
|
||||
if(! $channel) {
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
logger('public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
|
||||
|
||||
echo get_public_feed($channel,$params);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use DBA;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\Config;
|
||||
@@ -47,7 +48,7 @@ class Outbox extends Controller {
|
||||
|
||||
$params = [];
|
||||
|
||||
$params['begin'] = ((x($_REQUEST, 'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE);
|
||||
$params['begin'] = ((x($_REQUEST, 'date_begin')) ? $_REQUEST['date_begin'] : DBA::$dba->get_null_date());
|
||||
$params['end'] = ((x($_REQUEST, 'date_end')) ? $_REQUEST['date_end'] : '');
|
||||
$params['type'] = 'json';
|
||||
$params['pages'] = ((x($_REQUEST, 'pages')) ? intval($_REQUEST['pages']) : 0);
|
||||
|
||||
@@ -19,96 +19,128 @@ use Zotlabs\Web\Controller;
|
||||
class Owa extends Controller {
|
||||
|
||||
public function init(): void
|
||||
{
|
||||
{
|
||||
|
||||
$ret = [ 'success' => false ];
|
||||
|
||||
if (!$this->validateAuthorizationHeader()) {
|
||||
$this->error('Missing or invalid authorization header.');
|
||||
// try OpenWebAuth over RFC9421
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
|
||||
if ($sigdata && $sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
$portable_id = $sigdata['portable_id'];
|
||||
|
||||
if (!check_channelallowed($portable_id)) {
|
||||
json_return_and_die($ret, 'application/x-zot+json');
|
||||
}
|
||||
|
||||
if (!check_siteallowed($sigdata['signer'])) {
|
||||
json_return_and_die($ret, 'application/x-zot+json');
|
||||
}
|
||||
|
||||
$hubs = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
|
||||
WHERE hubloc_hash = '%s' ORDER BY hubloc_id DESC",
|
||||
dbesc($portable_id)
|
||||
);
|
||||
|
||||
if ($hubs) {
|
||||
logger('OWA RFC9421 success: ' . $hubs[0]['hubloc_id_url'], LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
Verify::create('owt', 0, $token, $hubs[0]['hubloc_id_url']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token, $result, $hubs[0]['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
}
|
||||
}
|
||||
|
||||
$_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 {
|
||||
if (!$this->validateAuthorizationHeader()) {
|
||||
$this->error('Missing or invalid authorization header.');
|
||||
}
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
$_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);
|
||||
}
|
||||
|
||||
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']);
|
||||
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 (!$ret['success']) {
|
||||
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']);
|
||||
}
|
||||
}
|
||||
|
||||
// Possible a reinstall?
|
||||
// In this case we probably already have an old hubloc
|
||||
// but not the new one yet.
|
||||
if (!$ret['success']) {
|
||||
|
||||
$found = discover_by_webbie($keyId);
|
||||
// Possible a reinstall?
|
||||
// In this case we probably already have an old hubloc
|
||||
// but not the new one yet.
|
||||
|
||||
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)
|
||||
);
|
||||
$found = discover_by_webbie($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 ($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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
79
Zotlabs/Module/Perfstats.php
Normal file
79
Zotlabs/Module/Perfstats.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/* Handler for perfstats requests.
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2026 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use DBA;
|
||||
use Zotlabs\Lib\DbStats;
|
||||
use Zotlabs\Lib\Queue;
|
||||
use Zotlabs\Lib\QueueWorkerStats;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
/**
|
||||
* Controller for the `/perfstats` module.
|
||||
*
|
||||
* Collects various performance stats for the site, and reponds with the stats
|
||||
* as a json array.
|
||||
*/
|
||||
class Perfstats extends Controller
|
||||
{
|
||||
public function init(): void {
|
||||
//
|
||||
// We only accept GET requests
|
||||
//
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||
http_status_exit(400, 'Unsupported method');
|
||||
}
|
||||
|
||||
//
|
||||
// We only accept json requests
|
||||
//
|
||||
if (getBestSupportedMimeType(['application/json']) === null) {
|
||||
http_status_exit(400, 'No supported format');
|
||||
}
|
||||
|
||||
//
|
||||
// Only admins should be given access
|
||||
//
|
||||
if (!is_site_admin()) {
|
||||
http_status(401, 'Access denied');
|
||||
json_return_and_die(['error' => 'access denied']);
|
||||
}
|
||||
|
||||
$data = $this->getStats();
|
||||
json_return_and_die($data);
|
||||
}
|
||||
|
||||
private function getStats(): array {
|
||||
$stats = [];
|
||||
|
||||
if (function_exists('sys_getloadavg')) {
|
||||
$stats['loadavg'] = sys_getloadavg();
|
||||
}
|
||||
|
||||
$stats['dbqueries'] = $this->getNumQueries();
|
||||
$stats['outqueue'] = Queue::count();
|
||||
|
||||
$qwstats = new QueueWorkerStats();
|
||||
$stats['queueworkers'] = $qwstats->active;
|
||||
$stats['workqsz'] = $qwstats->size;
|
||||
|
||||
// Return a timestamp, so that it is possible to infer
|
||||
// changes of the stats over time. A resolution of
|
||||
// seconds should be good enough for our purposes.
|
||||
$stats['ts'] = time();
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
private function getNumQueries(): int {
|
||||
$stats = DbStats::getStats();
|
||||
return $stats->getQueries();
|
||||
}
|
||||
}
|
||||
@@ -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.'));
|
||||
|
||||
@@ -60,26 +60,16 @@ class Profile extends Controller {
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/atom+xml',
|
||||
'title' => t('Posts and comments'),
|
||||
'href' => z_root() . '/feed/' . $which
|
||||
'href' => z_root() . '/feed/' . $which . '?top=0'
|
||||
]);
|
||||
|
||||
head_add_link([
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/atom+xml',
|
||||
'title' => t('Only posts'),
|
||||
'href' => z_root() . '/feed/' . $which . '?f=&top=1'
|
||||
'href' => z_root() . '/feed/' . $which . '?top=1'
|
||||
]);
|
||||
|
||||
|
||||
if (!$profile) {
|
||||
$x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1",
|
||||
dbesc(argv(1))
|
||||
);
|
||||
if ($x) {
|
||||
App::$profile = $x[0];
|
||||
}
|
||||
}
|
||||
|
||||
profile_load($which, $profile);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use DBA;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
@@ -340,7 +341,7 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
$with = ((x($_POST,'with')) ? escape_tags(trim($_POST['with'])) : '');
|
||||
|
||||
if(! strlen($howlong))
|
||||
$howlong = NULL_DATE;
|
||||
$howlong = DBA::$dba->get_null_date();
|
||||
else
|
||||
$howlong = datetime_convert(date_default_timezone_get(),'UTC',$howlong);
|
||||
|
||||
@@ -696,10 +697,9 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
$show_presence = ['show_presence', t('Reveal my online status'), $show_presence_val, '', [t('No'), t('Yes')]];
|
||||
}
|
||||
|
||||
$extra_fields = array();
|
||||
$q = q("select * from profdef where true");
|
||||
if($q) {
|
||||
$extra_fields = array();
|
||||
|
||||
foreach($q as $qq) {
|
||||
$mine = q("select v from profext where k = '%s' and hash = '%s' and channel_id = %d limit 1",
|
||||
dbesc($qq['field_name']),
|
||||
@@ -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"'),
|
||||
@@ -775,7 +775,7 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
'$marital' => marital_selector($r[0]['marital']),
|
||||
'$marital_min' => marital_selector_min($r[0]['marital']),
|
||||
'$with' => array('with', t("Who (if applicable)"), $r[0]['partner'], t('Examples: cathy123, Cathy Williams, cathy@example.com')),
|
||||
'$howlong' => array('howlong', t('Since (date)'), ($r[0]['howlong'] <= NULL_DATE ? '' : datetime_convert('UTC',date_default_timezone_get(),$r[0]['howlong']))),
|
||||
'$howlong' => array('howlong', t('Since (date)'), ($r[0]['howlong'] <= DBA::$dba->get_null_date() ? '' : datetime_convert('UTC',date_default_timezone_get(),$r[0]['howlong']))),
|
||||
'$sexual' => sexpref_selector($r[0]['sexual']),
|
||||
'$sexual_min' => sexpref_selector_min($r[0]['sexual']),
|
||||
'$about' => array('about', t('Tell us about yourself'), $r[0]['about']),
|
||||
@@ -833,6 +833,8 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
if($r) {
|
||||
|
||||
$profiles = '';
|
||||
|
||||
$tpl = get_markup_template('profile_entry.tpl');
|
||||
foreach($r as $rr) {
|
||||
$profiles .= replace_macros($tpl, array(
|
||||
@@ -841,7 +843,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>')
|
||||
));
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ class Profperm extends \Zotlabs\Web\Controller {
|
||||
if($switchtotext === false)
|
||||
$switchtotext = 400;
|
||||
|
||||
$change = 0;
|
||||
|
||||
if((argc() > 2) && intval(argv(1)) && intval(argv(2))) {
|
||||
$r = q("SELECT abook_id FROM abook WHERE abook_id = %d and abook_channel = %d limit 1",
|
||||
@@ -74,10 +75,11 @@ class Profperm extends \Zotlabs\Web\Controller {
|
||||
dbesc($profile['profile_guid'])
|
||||
);
|
||||
|
||||
$ingroup = array();
|
||||
if($r)
|
||||
$ingroup = [];
|
||||
if($r) {
|
||||
foreach($r as $member)
|
||||
$ingroup[] = $member['abook_id'];
|
||||
}
|
||||
|
||||
$members = $r;
|
||||
|
||||
@@ -104,68 +106,57 @@ class Profperm extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
|
||||
$members = $r;
|
||||
|
||||
$ingroup = array();
|
||||
if(count($r))
|
||||
$ingroup = [];
|
||||
if($r) {
|
||||
foreach($r as $member)
|
||||
$ingroup[] = $member['abook_id'];
|
||||
}
|
||||
|
||||
$o .= '<h2>' . t('Profile Visibility Editor') . '</h2>';
|
||||
|
||||
$o .= '<h3>' . t('Profile') . ' \'' . $profile['profile_name'] . '\'</h3>';
|
||||
|
||||
$o .= '<div id="prof-edit-desc">' . t('Click on a contact to add or remove.') . '</div>';
|
||||
|
||||
}
|
||||
|
||||
$o .= '<div id="prof-update-wrapper">';
|
||||
if($change)
|
||||
$o = '';
|
||||
|
||||
$o .= '<div id="prof-members-title">';
|
||||
$o .= '<h3>' . t('Visible To') . '</h3>';
|
||||
$o .= '</div>';
|
||||
$o .= '<div id="prof-members">';
|
||||
|
||||
$textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false);
|
||||
|
||||
foreach($members as $member) {
|
||||
if($member['xchan_url']) {
|
||||
$member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;';
|
||||
$o .= micropro($member,true,'mpprof', $textmode);
|
||||
}
|
||||
}
|
||||
$o .= '</div><div id="prof-members-end"></div>';
|
||||
$o .= '<hr id="prof-separator" />';
|
||||
|
||||
$o .= '<div id="prof-all-contcts-title">';
|
||||
$o .= '<h3>' . t("All Connections") . '</h3>';
|
||||
$o .= '</div>';
|
||||
$o .= '<div id="prof-all-contacts">';
|
||||
|
||||
$r = abook_connections(local_channel());
|
||||
|
||||
if($r) {
|
||||
$textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false);
|
||||
foreach($r as $member) {
|
||||
if(! in_array($member['abook_id'],$ingroup)) {
|
||||
$member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;';
|
||||
$o .= micropro($member,true,'mpprof',$textmode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$o .= '</div><div id="prof-all-contacts-end"></div>';
|
||||
$o .= '<h2>' . t('Profile Visibility Editor') . '</h2>';
|
||||
$o .= '<h3>' . t('Profile') . ' \'' . $profile['profile_name'] . '\'</h3>';
|
||||
$o .= '<div id="prof-edit-desc">' . t('Click on a contact to add or remove.') . '</div>';
|
||||
}
|
||||
|
||||
// Build template data
|
||||
$members_tpl = [];
|
||||
$textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false);
|
||||
if($members) {
|
||||
foreach($members as $member) {
|
||||
if($member['xchan_url']) {
|
||||
$member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;';
|
||||
$members_tpl[] = [ 'micro' => micropro($member, true, 'mpprof', $textmode) ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$all_members_tpl = [];
|
||||
$r = abook_connections(local_channel());
|
||||
if($r) {
|
||||
$textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false);
|
||||
foreach($r as $member) {
|
||||
if(! in_array($member['abook_id'], $ingroup)) {
|
||||
$member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;';
|
||||
$all_members_tpl[] = [ 'micro' => micropro($member, true, 'mpprof', $textmode) ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use tpl for the inner part
|
||||
$inner_html = replace_macros(get_markup_template('profile_members.tpl'), [
|
||||
'$visible_to' => t('Visible To'),
|
||||
'$all_connections' => t('All Connections'),
|
||||
'$members' => $members_tpl,
|
||||
'$all_members' => $all_members_tpl,
|
||||
]);
|
||||
|
||||
if($change) {
|
||||
echo $o;
|
||||
echo $inner_html;
|
||||
killme();
|
||||
}
|
||||
$o .= '</div>';
|
||||
|
||||
$o .= $inner_html;
|
||||
return $o;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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,16 @@ 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"
|
||||
);
|
||||
|
||||
|
||||
// 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 = items_by_parent_ids($r, blog_mode: $blog_mode);
|
||||
xchan_query($items);
|
||||
$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>';
|
||||
|
||||
@@ -142,7 +142,15 @@ class Regate extends \Zotlabs\Web\Controller {
|
||||
|
||||
if (($flags & ACCOUNT_PENDING ) == ACCOUNT_PENDING) {
|
||||
$nextpage = 'regate/' . bin2hex($did2) . $didx;
|
||||
q("COMMIT");
|
||||
$approve = send_reg_approval_email_from_register($r['reg_id']);
|
||||
if ($approve['success']) {
|
||||
q("COMMIT");
|
||||
} else {
|
||||
q("ROLLBACK");
|
||||
$msg_code = 'ZAR1237E';
|
||||
$msg = t('Account verification notify error');
|
||||
zar_log($msg_code . ' ' . $msg . ': ' . print_r($approve, true));
|
||||
}
|
||||
}
|
||||
elseif (($flags ^ REGISTER_AGREED) == 0) {
|
||||
|
||||
@@ -375,7 +383,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 +394,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 +464,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();
|
||||
|
||||
@@ -1,37 +1,38 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use DBA;
|
||||
|
||||
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) {
|
||||
|
||||
if($account['account_password_changed'] > DBA::$dba->get_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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use DBA;
|
||||
|
||||
class Removeme extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -29,7 +30,7 @@ class Removeme extends \Zotlabs\Web\Controller {
|
||||
if(! ($x && $x['account']))
|
||||
return;
|
||||
|
||||
if($account['account_password_changed'] > NULL_DATE) {
|
||||
if($account['account_password_changed'] > DBA::$dba->get_null_date()) {
|
||||
$d1 = datetime_convert('UTC','UTC','now - 48 hours');
|
||||
if($account['account_password_changed'] > $d1) {
|
||||
notice( t('Channel removals are not allowed within 48 hours of changing the account password.') . EOL);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user