mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 09:01:15 -04:00
Compare commits
1375 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ee82b5ccc | ||
|
|
d4401faed5 | ||
|
|
9daecfbb46 | ||
|
|
2adb8ffbb5 | ||
|
|
2e1a04f6e3 | ||
|
|
9f0fc77ac6 | ||
|
|
bb303ebc4c | ||
|
|
b8683f73ce | ||
|
|
2eae33736b | ||
|
|
4dbcbbb1af | ||
|
|
8af931a4b9 | ||
|
|
b80cb0adad | ||
|
|
b5f7e55c2b | ||
|
|
3952aba824 | ||
|
|
15db8dd945 | ||
|
|
1876762216 | ||
|
|
492e8df555 | ||
|
|
7667af5659 | ||
|
|
92ca97ea6b | ||
|
|
bf57bd34f9 | ||
|
|
f1bd35b555 | ||
|
|
5a77f23186 | ||
|
|
6b605fecb0 | ||
|
|
496dade675 | ||
|
|
82b8ed2652 | ||
|
|
2625fe9527 | ||
|
|
320019fca3 | ||
|
|
78f2bb46f9 | ||
|
|
88c1cda002 | ||
|
|
6f65d2d6ef | ||
|
|
674522c8da | ||
|
|
47c902a5ea | ||
|
|
0c7731bb76 | ||
|
|
62582509cd | ||
|
|
67d73f74ac | ||
|
|
1553bc708f | ||
|
|
99728bf038 | ||
|
|
965e643c71 | ||
|
|
8d283e0be5 | ||
|
|
0cd682d85e | ||
|
|
9aff1d4024 | ||
|
|
b0a2bf47c8 | ||
|
|
3d29c498e9 | ||
|
|
acf683a7d3 | ||
|
|
fdeab5b2d1 | ||
|
|
fa7c8e93f1 | ||
|
|
fd6b252b36 | ||
|
|
f7a29f7539 | ||
|
|
de9e2c27ea | ||
|
|
0376b5d442 | ||
|
|
b20ed4f455 | ||
|
|
a574c79f9e | ||
|
|
9c9ca7728c | ||
|
|
7fc1d58b10 | ||
|
|
782765e377 | ||
|
|
e2dbf0a785 | ||
|
|
1680bac8b5 | ||
|
|
231384a58f | ||
|
|
6edeea4b42 | ||
|
|
7559d6bb5c | ||
|
|
1c9c0dc70e | ||
|
|
bf4227bfef | ||
|
|
c296d4bbed | ||
|
|
68452fb07b | ||
|
|
7f98cd606b | ||
|
|
d0ae7a0493 | ||
|
|
81e79eec04 | ||
|
|
7d70f2f0f2 | ||
|
|
016a11ad27 | ||
|
|
1637e61681 | ||
|
|
1ec0e91405 | ||
|
|
1774140307 | ||
|
|
8152da1275 | ||
|
|
eb10820195 | ||
|
|
9d33456c89 | ||
|
|
3dd9559d9f | ||
|
|
51ac502d97 | ||
|
|
955ee217e3 | ||
|
|
6d8bfe58ef | ||
|
|
f98f540256 | ||
|
|
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 | ||
|
|
0ea3f3d36d | ||
|
|
cb7dc2059a | ||
|
|
e988bc9fae | ||
|
|
cb23a9e235 | ||
|
|
8d9623674d | ||
|
|
6d181ee69e | ||
|
|
2d97f8fa25 | ||
|
|
98a3c97820 | ||
|
|
89e1328ed0 | ||
|
|
5cb4db0353 | ||
|
|
dc43cd9a85 | ||
|
|
5a6a7386a8 | ||
|
|
4f545e31dd | ||
|
|
437c0a8913 | ||
|
|
268fccdb30 | ||
|
|
bb7689be93 | ||
|
|
bd63af69b2 | ||
|
|
e5d4358d61 | ||
|
|
0fa4962620 | ||
|
|
fe4d6229a4 | ||
|
|
99a1569d07 | ||
|
|
9fb5cd12be | ||
|
|
d85c737db7 | ||
|
|
794b456b8a | ||
|
|
a0cb5fcb3f | ||
|
|
0d382634ec | ||
|
|
225c83dfbe | ||
|
|
e736945f1d | ||
|
|
cb0102b971 | ||
|
|
8b46767d30 | ||
|
|
3f39d0d249 | ||
|
|
3130a94a4c | ||
|
|
d44c004bd0 | ||
|
|
c655046e1f | ||
|
|
b32c1c1e22 | ||
|
|
38f040f9b5 | ||
|
|
7dcaebf281 | ||
|
|
fad5f98405 | ||
|
|
ea07bd1693 | ||
|
|
deaab14c5f | ||
|
|
8258b8b088 | ||
|
|
db5c217a21 | ||
|
|
724ee7dbab | ||
|
|
fb9fe0d3c4 | ||
|
|
9019636449 | ||
|
|
933b4fbcfe | ||
|
|
7675ed0145 | ||
|
|
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 | ||
|
|
7959dd9f57 | ||
|
|
fde03c7ae0 | ||
|
|
7fcc770fbf | ||
|
|
dcb09a8b39 | ||
|
|
57c22f4d0f | ||
|
|
ed1cfa5c7b | ||
|
|
3878dbd6bd | ||
|
|
554577fad7 | ||
|
|
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 | ||
|
|
866d88de53 | ||
|
|
69acee497d | ||
|
|
6c74672d40 | ||
|
|
6320506c27 | ||
|
|
1ee0f3ce1d | ||
|
|
0730d31c22 | ||
|
|
a2a8b2e9fb | ||
|
|
8821fa9a0e | ||
|
|
363100a612 | ||
|
|
1f7ac5e787 | ||
|
|
2233a0317e | ||
|
|
498ef78e6f | ||
|
|
8a606365c8 | ||
|
|
9c27f94709 | ||
|
|
a99e067b91 | ||
|
|
831f4324ae | ||
|
|
ad205abd90 | ||
|
|
231f4a28eb | ||
|
|
95b52b6aa9 | ||
|
|
385c23a2b6 | ||
|
|
3a81edbcb0 | ||
|
|
2f377089e6 | ||
|
|
6427e84053 | ||
|
|
88577e1e97 | ||
|
|
3653ae1af0 | ||
|
|
f2aa42f18a | ||
|
|
aa5bd9bbfc | ||
|
|
73b931ed14 | ||
|
|
73fafd9f2b | ||
|
|
ef05cecaeb | ||
|
|
5b6d70fd60 | ||
|
|
cfb8bf3ab9 | ||
|
|
3cf7e09609 | ||
|
|
d11b05de71 | ||
|
|
2865dc45eb | ||
|
|
ba96b2ce85 | ||
|
|
d9f467f215 | ||
|
|
23a8c2f0a8 | ||
|
|
76856188e1 | ||
|
|
f3d8838256 | ||
|
|
2871ef2897 | ||
|
|
aa7358c837 | ||
|
|
57b553a79f | ||
|
|
f08498440a | ||
|
|
e9c07c554a | ||
|
|
a570ef4691 | ||
|
|
7cf7aa397e | ||
|
|
03af9d415f | ||
|
|
e5acf404ab | ||
|
|
2e89cfe5ed | ||
|
|
21951ec5ee | ||
|
|
9e33fa8ee2 | ||
|
|
1658244b09 | ||
|
|
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 | ||
|
|
1a68dbccf1 | ||
|
|
fc87ef282e | ||
|
|
ab0e5e3eee | ||
|
|
356b6127d3 | ||
|
|
87c62db41e | ||
|
|
0d3855cd63 | ||
|
|
ffce0a705b | ||
|
|
49e65902d7 | ||
|
|
2e1fd79c7a | ||
|
|
0c577b5fd0 | ||
|
|
3178a96a89 | ||
|
|
c1cec623bb | ||
|
|
d3cc098070 | ||
|
|
69e7812646 | ||
|
|
d39320475c | ||
|
|
0faf47b3ca | ||
|
|
660ff3da7b | ||
|
|
7ec8a2267a | ||
|
|
4a35764e13 | ||
|
|
57e2904cc0 | ||
|
|
b49c844a23 | ||
|
|
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 | ||
|
|
05800a5ff3 | ||
|
|
120292bd6c | ||
|
|
3c722f9aa7 | ||
|
|
185f53d298 | ||
|
|
3ae42d471a | ||
|
|
0a817f952e | ||
|
|
bc7f8b15a8 | ||
|
|
02111ad649 | ||
|
|
eafa1d56c3 | ||
|
|
5b6a38aa2d | ||
|
|
37b9919905 | ||
|
|
283c018d07 | ||
|
|
51c79aecac | ||
|
|
9343f00918 | ||
|
|
eeef6cfd00 | ||
|
|
96c7912fa6 | ||
|
|
3f7ed72ece | ||
|
|
3385c694aa | ||
|
|
a922f5ca6c | ||
|
|
88977a406c | ||
|
|
e98f019b16 | ||
|
|
50f5fcb16b | ||
|
|
bf35a661bf | ||
|
|
ecc94cdecd | ||
|
|
e79a70d2b1 | ||
|
|
6916a825ee | ||
|
|
b5a798f068 | ||
|
|
e5c54fadea | ||
|
|
f2217e9016 | ||
|
|
4d6bebb846 | ||
|
|
2e9b1d25e1 | ||
|
|
8604ba016e | ||
|
|
cc35afa4c9 | ||
|
|
f01c5ad0c1 | ||
|
|
7b6a8fdba1 | ||
|
|
2c9f184a09 | ||
|
|
6f158f37c9 | ||
|
|
f88d2ba0c4 | ||
|
|
170f157aae | ||
|
|
3eeaca4aab | ||
|
|
c383e6af80 | ||
|
|
eb3dfb2488 | ||
|
|
ae8e9bc353 | ||
|
|
88227b9155 | ||
|
|
ae77ab7f20 | ||
|
|
308380fe52 | ||
|
|
161cfcd64d | ||
|
|
d16d1fdcd5 | ||
|
|
06c0652b05 | ||
|
|
a2fb2e04f3 | ||
|
|
b376f810bf | ||
|
|
0c2bcda431 | ||
|
|
22cb0d3c6b | ||
|
|
b6b4eb4c22 | ||
|
|
d566199423 | ||
|
|
35be83c5f6 | ||
|
|
76eed3c06c | ||
|
|
d994e1be48 | ||
|
|
7b5a638e00 | ||
|
|
fa4c86eabf | ||
|
|
9cf610280c | ||
|
|
a55bba7aa8 | ||
|
|
2958ea8c89 | ||
|
|
81a12be654 | ||
|
|
9f99e401bc | ||
|
|
d782229ba0 | ||
|
|
52291fd371 | ||
|
|
e0298a4378 | ||
|
|
08b7eb52c7 | ||
|
|
43ebf69d09 | ||
|
|
18ae629f19 | ||
|
|
8deedd1979 | ||
|
|
525594d529 | ||
|
|
1162615c52 | ||
|
|
c462c928e0 | ||
|
|
fcb0ef9633 | ||
|
|
8a4273a2f5 | ||
|
|
3014ae2071 | ||
|
|
d396043faf | ||
|
|
2054359f6c | ||
|
|
9a3735cd37 | ||
|
|
222b74ec05 | ||
|
|
cb491c53f7 | ||
|
|
e6c8c47721 | ||
|
|
0a98a49eeb | ||
|
|
af5733888c | ||
|
|
c346210735 | ||
|
|
6028f0490e | ||
|
|
7782183ae3 | ||
|
|
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 | ||
|
|
9904eba277 | ||
|
|
8d25b6eae4 | ||
|
|
059113d2a8 | ||
|
|
f60dff788e | ||
|
|
9c20b4809a | ||
|
|
2695094d16 | ||
|
|
1650809cd8 | ||
|
|
c5fb8eafac | ||
|
|
7d6202be13 | ||
|
|
e948aaf751 | ||
|
|
3789017ca0 | ||
|
|
48f5acced3 | ||
|
|
13e2d2f654 | ||
|
|
39f9a38b23 | ||
|
|
590c0ea778 | ||
|
|
f36d8e4bd2 | ||
|
|
4e3bec8a35 | ||
|
|
eec918bf4a | ||
|
|
40c63a7f12 | ||
|
|
3d0621eb8c | ||
|
|
030c02dfdc | ||
|
|
00c1509549 | ||
|
|
8122c40252 | ||
|
|
787c63b7ae | ||
|
|
a71f5e123a | ||
|
|
0c97792ca7 | ||
|
|
84d63b3b67 | ||
|
|
63aa50eb8d | ||
|
|
7fb13f23fe | ||
|
|
65156a0e4d | ||
|
|
e3eebcd95d | ||
|
|
9eff1a08d4 | ||
|
|
cfcac590c3 | ||
|
|
872415bffe | ||
|
|
a46b781664 | ||
|
|
b77fac43c8 | ||
|
|
2b4b409c01 | ||
|
|
67aa547c48 | ||
|
|
e288f33776 | ||
|
|
a5aab4c30e | ||
|
|
cf7613b3e0 | ||
|
|
fa01a2b348 | ||
|
|
65c8de3410 | ||
|
|
d9b262348f | ||
|
|
ea9d2a0acf | ||
|
|
5d55006be8 | ||
|
|
d9ced0c6bf | ||
|
|
8d4d1b17c7 | ||
|
|
453f6a08a3 | ||
|
|
b6560e5456 | ||
|
|
b805f48c32 | ||
|
|
33b78a4943 | ||
|
|
48b187ccd8 | ||
|
|
f680bba3e6 | ||
|
|
09aabc6b41 | ||
|
|
0dd456c653 | ||
|
|
97ba14cbe0 | ||
|
|
ee6367a549 | ||
|
|
fc52d1b44f | ||
|
|
bfce562a46 | ||
|
|
8d8a7f44e1 | ||
|
|
a13bf6a3fe | ||
|
|
0edf761499 | ||
|
|
bf76d5981f | ||
|
|
33fcb43173 | ||
|
|
ffae47f523 | ||
|
|
c07cdb30fa | ||
|
|
0a17b83578 | ||
|
|
dc076a4c00 | ||
|
|
a550c7c853 | ||
|
|
7a3d59bff3 | ||
|
|
82a3b71a51 | ||
|
|
e39b2eb7b9 | ||
|
|
9f8248cc9c | ||
|
|
71e4326606 | ||
|
|
7eb6f9b11d | ||
|
|
4625ffa6b4 | ||
|
|
3e6a646603 | ||
|
|
03d1f3383e | ||
|
|
174469970a | ||
|
|
89b254dc1c | ||
|
|
8e51988e96 | ||
|
|
52e279f443 | ||
|
|
4efa853690 | ||
|
|
2d2c9fa519 | ||
|
|
27efb887d2 | ||
|
|
ccd52584a4 | ||
|
|
ab0fdb13d4 | ||
|
|
2bca44ed25 | ||
|
|
eab08d0bcb | ||
|
|
d3f00704bd | ||
|
|
1e1a7109a9 | ||
|
|
0165f44063 | ||
|
|
8fc0e41beb | ||
|
|
3ad63a6e82 | ||
|
|
392cb020aa | ||
|
|
884b612ffc | ||
|
|
ae0d138d2a | ||
|
|
48ef4744ac | ||
|
|
a17cb75baf | ||
|
|
169c971cb1 | ||
|
|
3ebbb91ae9 | ||
|
|
051cef79fc | ||
|
|
f66f0e398b | ||
|
|
553b3f6faa | ||
|
|
2980827925 | ||
|
|
45a78dcbc0 | ||
|
|
c9ebb23b69 | ||
|
|
bc998eacd0 | ||
|
|
648979467a | ||
|
|
5c0ff6f584 | ||
|
|
58985f2200 | ||
|
|
3940187d19 | ||
|
|
1215e8a030 | ||
|
|
5b6e27233a | ||
|
|
de9b10e850 | ||
|
|
36a1d98c52 | ||
|
|
b1f2f67a04 | ||
|
|
bd10c1e40a | ||
|
|
e146eaa8f8 | ||
|
|
92e21c4f3d | ||
|
|
55265c8a3e | ||
|
|
c3cc624621 | ||
|
|
b466932e37 | ||
|
|
a3248e8b3b | ||
|
|
9ec2db7c97 | ||
|
|
9bd94287dd | ||
|
|
faca95b21c | ||
|
|
79f8b06ede | ||
|
|
a2dde34b1b | ||
|
|
fb5824417e | ||
|
|
804b4effa2 | ||
|
|
4c8e1de4c6 | ||
|
|
d9c69b747d | ||
|
|
0e4be679e4 | ||
|
|
14360c4735 | ||
|
|
2da55d3bd8 | ||
|
|
e9222d0d9a | ||
|
|
93f72a53f5 | ||
|
|
93c4bd4692 | ||
|
|
486c21b519 | ||
|
|
7785487d77 | ||
|
|
9756023e39 | ||
|
|
bb0a22ee58 | ||
|
|
e88ae54bef | ||
|
|
d37d181d94 | ||
|
|
d59d808883 | ||
|
|
b59fe77906 | ||
|
|
1941b4f026 | ||
|
|
5c82229e34 | ||
|
|
66d502d8e1 | ||
|
|
66acfc66ce | ||
|
|
2e13640ab4 | ||
|
|
277b4f7d10 | ||
|
|
edf2a6db1b | ||
|
|
8ad000ec70 | ||
|
|
563628fef8 | ||
|
|
15b6353c1c | ||
|
|
1a86348a6c | ||
|
|
a80ab5887c | ||
|
|
475ae7ba13 | ||
|
|
e107298125 | ||
|
|
428ffa5e35 | ||
|
|
0bffe6e019 | ||
|
|
9e2f3dc05f | ||
|
|
9fa18a5557 | ||
|
|
9608ab27c4 | ||
|
|
464b331deb | ||
|
|
0189d04614 | ||
|
|
cbb3ad1620 | ||
|
|
c0f9d55cfb | ||
|
|
0da51e0f71 | ||
|
|
9014a288b0 | ||
|
|
dcef9f61b5 | ||
|
|
3d80db0cdc | ||
|
|
3a2f787f96 | ||
|
|
f7a9b84943 | ||
|
|
46e6600169 | ||
|
|
243a2a9bdf | ||
|
|
5338793883 | ||
|
|
9acc73b273 | ||
|
|
5cfb3842f1 | ||
|
|
25b089c1a9 | ||
|
|
67a9292aaa | ||
|
|
81dda15669 | ||
|
|
5b7f8d986c | ||
|
|
5dee600735 | ||
|
|
01da60b385 | ||
|
|
951800eca6 | ||
|
|
72c47cd8db | ||
|
|
e3a8668c32 | ||
|
|
fd9977eada | ||
|
|
bd3304ff94 | ||
|
|
c9a8914b07 | ||
|
|
b21b9260d9 | ||
|
|
b5c07e4c01 | ||
|
|
28b5b0cab5 | ||
|
|
39d0a3f1f6 | ||
|
|
ce9d67f7b1 | ||
|
|
8268ed1ba7 | ||
|
|
6c1d0851d7 | ||
|
|
3bc0fd5db4 | ||
|
|
4c3f3d1477 | ||
|
|
17411a501c | ||
|
|
d446f171c5 | ||
|
|
b24b409a01 | ||
|
|
3791dfab3a | ||
|
|
31a146b23a | ||
|
|
e52714ed16 | ||
|
|
2c17d0b031 | ||
|
|
57e69372d3 | ||
|
|
43acb86aab | ||
|
|
e339fbcc46 | ||
|
|
4e6696b049 | ||
|
|
fbc79e36e0 | ||
|
|
c9d4b068c2 | ||
|
|
b6dbbbc82f | ||
|
|
954d92c354 | ||
|
|
8dbebc2b42 | ||
|
|
14207c68ca | ||
|
|
0ed08274f1 | ||
|
|
2a152e0803 | ||
|
|
a0c54c5f04 | ||
|
|
ac8c80ddbe | ||
|
|
ebad9d56c9 | ||
|
|
0481901b59 | ||
|
|
0534fe6886 | ||
|
|
6e51571309 | ||
|
|
fe30b54975 | ||
|
|
b00ae997a5 | ||
|
|
b5b7d0cda9 | ||
|
|
300d461a1a | ||
|
|
e516c1352f | ||
|
|
4b4cac63fd | ||
|
|
47f109451d | ||
|
|
17183cc5dc | ||
|
|
939e5d9ca5 | ||
|
|
600209e21e | ||
|
|
12c88c06d8 | ||
|
|
229efddbf1 | ||
|
|
abb67a4565 | ||
|
|
2e324d4cef | ||
|
|
d4d1a7523d | ||
|
|
7a3f2c1ba9 | ||
|
|
9f473fc204 | ||
|
|
35a05073f2 | ||
|
|
472484dde0 | ||
|
|
5c3bdbd1e0 | ||
|
|
ec02453d37 | ||
|
|
21b60bf119 | ||
|
|
5db3f93be9 | ||
|
|
d25314c75b | ||
|
|
e20327d267 | ||
|
|
8ab3ad6531 | ||
|
|
bf008465ad | ||
|
|
a29a1c768d | ||
|
|
90bc987ea7 | ||
|
|
46fdce4402 | ||
|
|
38c947590e | ||
|
|
c5faa012b5 | ||
|
|
2f0a47e583 | ||
|
|
541a0f6476 | ||
|
|
065f85bab1 | ||
|
|
160c40b580 | ||
|
|
005d4ad351 | ||
|
|
90a1dad02c | ||
|
|
4daba84223 | ||
|
|
fc182f1b07 | ||
|
|
0207c02420 | ||
|
|
68135c28da | ||
|
|
274bfa9024 | ||
|
|
4bb28a21c4 | ||
|
|
0e50b1d10c | ||
|
|
8f4c3a2f88 | ||
|
|
73006ccdf5 | ||
|
|
1006ebbf61 | ||
|
|
e530476e6c | ||
|
|
e0a91bed7a | ||
|
|
168ec53686 | ||
|
|
4d1be3aea5 | ||
|
|
e8f816a981 | ||
|
|
e649ba5b13 | ||
|
|
92ce66e766 | ||
|
|
1411eafa9b | ||
|
|
20db45c815 | ||
|
|
4acdb8fb10 | ||
|
|
f4495fd441 | ||
|
|
e2ae8f0c4d | ||
|
|
074dc440cc | ||
|
|
d7fa6f6709 | ||
|
|
40a9989be2 | ||
|
|
d1648927b5 | ||
|
|
ecde4a3ded | ||
|
|
687cda3673 | ||
|
|
47cdef390a | ||
|
|
05a5b644bf | ||
|
|
84556854e8 | ||
|
|
314443d41e | ||
|
|
c23a71c936 | ||
|
|
12b33a23de | ||
|
|
a305c20e08 | ||
|
|
e2cfe245b7 | ||
|
|
12b24e0e5e | ||
|
|
d5291e9b07 | ||
|
|
a1818b1a29 | ||
|
|
e8eb283fd8 | ||
|
|
96d5370122 | ||
|
|
2bcb6a4fed | ||
|
|
aee396421a | ||
|
|
897568a087 | ||
|
|
a5c1b669b4 | ||
|
|
2aee659cbd | ||
|
|
b117cf9dc7 | ||
|
|
c2ce1d9881 | ||
|
|
2ed8908127 | ||
|
|
6588e272db | ||
|
|
c13645f136 | ||
|
|
8cee16be1b | ||
|
|
45c0091d3d | ||
|
|
44232677c8 | ||
|
|
16603ca854 | ||
|
|
75184355d0 | ||
|
|
1988d21e6c | ||
|
|
bccac55cf9 | ||
|
|
19eeadfe5b | ||
|
|
2693e9e990 | ||
|
|
04741c761a | ||
|
|
8f890fb6fa | ||
|
|
1afb2a4ce8 | ||
|
|
8ffab25f5d | ||
|
|
7d41deebce | ||
|
|
7e48caae6b | ||
|
|
afbeb58c16 | ||
|
|
9008760aa6 | ||
|
|
6b98b799c8 | ||
|
|
9f49d313f5 | ||
|
|
a5f0253aef | ||
|
|
4e6f871bc4 | ||
|
|
803cd74b48 | ||
|
|
0bfdb958f5 | ||
|
|
becd4c6ffd | ||
|
|
3f411787c1 | ||
|
|
5782a674b0 | ||
|
|
fc79e47d88 | ||
|
|
1c45030c58 | ||
|
|
18f3887050 | ||
|
|
2cc962e53a | ||
|
|
5b93aa1148 | ||
|
|
4daa03f025 | ||
|
|
8ae9df3bb7 | ||
|
|
25d9d3ba1b | ||
|
|
26ce231951 | ||
|
|
fb9464437e | ||
|
|
4dff1a1e5b | ||
|
|
2c05638776 | ||
|
|
5cbd42bbc4 | ||
|
|
ac6720e118 | ||
|
|
5281f4dd9b | ||
|
|
c12ef4fbf4 | ||
|
|
424b31b7f0 | ||
|
|
20ee1a5b5b | ||
|
|
2cd779cbe9 |
@@ -27,23 +27,21 @@ if you look for more choices. The main differences are:
|
||||
- graphical installer whiptail
|
||||
- The script stops (fails) if it finds results of a previous installation. (The [debian-setup.sh](https://framagit.org/ojrandom/core/-/tree/dev/.debianinstall) will just jump over it.)
|
||||
- If something fails the script tries to clean up everything that was installed up to the point of failure. (That might cause trouble if certbot registered a certificate already.)
|
||||
- The script under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall) seems to be an older version of the scripts used for Streams
|
||||
+ [autoinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/autoinstall)
|
||||
+ [easyinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/easyinstall)
|
||||
- The script under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall) seems to be an older version of the scripts used for Streams, i.e. [autoinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/autoinstall) and [easyinstall](https://codeberg.org/streams/streams/src/branch/dev/contrib/easyinstall)
|
||||
|
||||
## Preconditions
|
||||
|
||||
Hardware
|
||||
|
||||
+ internet connection and router at home
|
||||
+ computer connected to your router (a Raspberry 3 will do for very small Hubs)
|
||||
+ computer connected to your router (a Raspberry 4 will do for very small Hubs)
|
||||
|
||||
Software
|
||||
|
||||
+ fresh installation of Debian 12 (bookworm)
|
||||
+ fresh installation of Debian 12 (bookworm) or Raspberry Pi OS
|
||||
+ router with open ports 80 and 443 for your web server
|
||||
|
||||
You can of course run the script on a VPS or any distant server as long as the above sotfware requirements are satisfied.
|
||||
You can of course run the script on a VPS or any distant server as long as the above software requirements are satisfied.
|
||||
|
||||
## How to run the script
|
||||
|
||||
@@ -82,6 +80,11 @@ Switch the verification off
|
||||
|
||||
util/config system verify_email 0
|
||||
|
||||
Check if updates from the repository do work
|
||||
|
||||
util/udall
|
||||
|
||||
|
||||
## What the script will do for you...
|
||||
|
||||
+ install everything required by your hubzilla instance, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||
@@ -101,7 +104,7 @@ The script is known to work without adjustments with
|
||||
|
||||
+ Hardware
|
||||
- standard PC with Debian 12 (bookworm)
|
||||
- Raspberry 4 with Raspbian, Debian 12 (TODO: needs confirmation after swich to Debian12)
|
||||
- Raspberry 5 with Raspberry Pi OS, Debian 12
|
||||
- for tesing purposes: under localhost inside a virtual machine, [KVM](https://wiki.debian.org/KVM)
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
@@ -151,8 +154,3 @@ It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
## Reminder for Different Web Wervers
|
||||
|
||||
For those of you who feel adventurous enough to use a different web server (i.e. Lighttpd...), don't forget that this script will install Apache or Nginx and that you can only have one web server listening to ports 80 & 443. Also, don't forget to tweak your daily shell script in /var/www/ accordingly.
|
||||
|
||||
@@ -93,9 +93,8 @@ freedns_key=
|
||||
# If left empty, both your database and user will be named after your zot instance (hubzilla, zap or misty)
|
||||
# Use custom name, at least fo the database, if you plan to run more than one hub/instance on the same server
|
||||
#
|
||||
zotserver_db_name=
|
||||
zotserver_db_user=
|
||||
zotserver_db_pass=$db_pass
|
||||
db_name=hubzilla
|
||||
db_user=hubzilla
|
||||
#
|
||||
#
|
||||
# Password for package mysql-server
|
||||
|
||||
@@ -150,7 +150,7 @@ function install_sendmail {
|
||||
function install_php {
|
||||
# openssl and mbstring are included in libapache2-mod-php
|
||||
print_info "installing php..."
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip"
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip php-intl php-bcmath"
|
||||
phpversion=$(php -v|grep --only-matching --perl-regexp "(PHP )\d+\.\\d+\.\\d+"|cut -c 5-7)
|
||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/$phpversion/apache2/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/$phpversion/apache2/php.ini
|
||||
@@ -160,8 +160,8 @@ function install_composer {
|
||||
print_info "We check if Composer is already downloaded"
|
||||
if [ ! -f /usr/local/bin/composer ]
|
||||
then
|
||||
EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
|
||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
EXPECTED_CHECKSUM="`wget -qO- https://composer.github.io/installer.sig`"
|
||||
wget https://getcomposer.org/installer -O composer-setup.php
|
||||
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
||||
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
|
||||
then
|
||||
@@ -171,6 +171,7 @@ function install_composer {
|
||||
fi
|
||||
php composer-setup.php --quiet
|
||||
RESULT=$?
|
||||
composer --version
|
||||
rm composer-setup.php
|
||||
# exit $RESULT
|
||||
# We install Composer globally
|
||||
@@ -181,7 +182,7 @@ function install_composer {
|
||||
fi
|
||||
cd $install_path
|
||||
export COMPOSER_ALLOW_SUPERUSER=1;
|
||||
/usr/local/bin/composer install --no-dev
|
||||
/usr/local/bin/composer install --no-dev --quiet
|
||||
/usr/local/bin/composer show
|
||||
export COMPOSER_ALLOW_SUPERUSER=0;
|
||||
}
|
||||
@@ -256,12 +257,18 @@ function create_zotserver_db {
|
||||
then
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $db_user@localhost IDENTIFIED BY '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $db_name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
else
|
||||
echo "database $db_name does exist already"
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $db_user@localhost IDENTIFIED BY '$db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $db_name.* to $db_user@localhost identified by '$db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -301,10 +308,19 @@ function install_run_selfhost {
|
||||
# https://carol.selfhost.de/update?username=123456&password=supersafe
|
||||
#
|
||||
# the prefered way
|
||||
wget --output-document=$selfhostdir/$selfhostscript http://jonaspasche.de/selfhost-updater
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
if [ ! -f $selfhostdir/$selfhostscript ]
|
||||
then
|
||||
wget --output-document=$selfhostdir/$selfhostscript https://jonaspasche.de/selfhost-updater
|
||||
if [ ! -s $selfhostdir/$selfhostscript ]
|
||||
then
|
||||
die "Failed to download selfHOST file for dynDNS"
|
||||
fi
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
print_info "Wrote file to update dynamic IP. File: $selfhostdir/$selfhostscript"
|
||||
fi
|
||||
print_info "executing $selfhostdir/$selfhostscript update..."
|
||||
bash $selfhostdir/$selfhostscript update
|
||||
fi
|
||||
}
|
||||
@@ -380,7 +396,7 @@ function install_letsencrypt {
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||
fi
|
||||
nocheck_install "certbot python-certbot-apache"
|
||||
nocheck_install "certbot python3-certbot-apache"
|
||||
print_info "run certbot ..."
|
||||
certbot --apache -w $install_path -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
|
||||
service apache2 restart
|
||||
@@ -435,7 +451,7 @@ function configure_cron_daily {
|
||||
echo "echo \" \"" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - stopping apache and mysql...\"" >> /var/www/$cron_job
|
||||
echo "service apache2 stop" >> /var/www/$cron_job
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /var/www/$cron_job
|
||||
echo "systemctl stop mysql.service # to avoid inconsistencies" >> /var/www/$cron_job
|
||||
echo "#" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$cron_job
|
||||
echo "certbot renew --noninteractive" >> /var/www/$cron_job
|
||||
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -48,9 +48,10 @@ doc/html/
|
||||
.zotshrc
|
||||
# external repositories for themes/addons
|
||||
extend/
|
||||
# files generated by phpunit
|
||||
|
||||
# exclude test results and cache
|
||||
tests/.cache
|
||||
tests/.phpunit.result.cache
|
||||
tests/.phpunit*
|
||||
tests/results/
|
||||
|
||||
## exclude IDE files
|
||||
@@ -67,7 +68,6 @@ nbproject/
|
||||
# PHPStorm
|
||||
.idea/
|
||||
|
||||
|
||||
## composer
|
||||
# locally installed composer binary
|
||||
composer.phar
|
||||
@@ -87,6 +87,7 @@ vendor/bin/php-parse
|
||||
vendor/bin/phpcbf
|
||||
vendor/bin/phpcs
|
||||
vendor/bin/phpmd
|
||||
vendor/bin/phpstan*
|
||||
vendor/bin/phpunit
|
||||
vendor/composer/pcre/
|
||||
vendor/composer/xdebug-handler/
|
||||
@@ -98,18 +99,11 @@ vendor/pdepend/
|
||||
vendor/phar-io/
|
||||
vendor/php-mock/
|
||||
vendor/phpmd/
|
||||
vendor/phpstan
|
||||
vendor/phpunit/
|
||||
vendor/psr/container/
|
||||
vendor/sebastian/
|
||||
vendor/squizlabs/
|
||||
vendor/symfony/config/
|
||||
vendor/symfony/dependency-injection/
|
||||
vendor/symfony/deprecation-contracts/
|
||||
vendor/symfony/filesystem/
|
||||
vendor/symfony/polyfill-ctype/
|
||||
vendor/symfony/polyfill-mbstring/
|
||||
vendor/symfony/polyfill-php80/
|
||||
vendor/symfony/service-contracts/
|
||||
vendor/theseer/
|
||||
# /info is a directory containing site-specific HTML documents
|
||||
/info/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
stages:
|
||||
- pretest
|
||||
- test
|
||||
- deploy
|
||||
|
||||
@@ -25,22 +26,6 @@ variables:
|
||||
POSTGRES_USER: ci-user
|
||||
POSTGRES_PASSWORD: ci-pass
|
||||
|
||||
|
||||
before_script:
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- apt-get update
|
||||
- apt-get install -yqq libicu-dev libjpeg-dev libpng-dev libpq-dev libyaml-dev libzip-dev mariadb-client postgresql-client unzip zip
|
||||
- pecl install xdebug yaml
|
||||
- docker-php-ext-enable xdebug yaml
|
||||
- docker-php-ext-install gd bcmath intl pdo_mysql pdo_pgsql zip
|
||||
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php ./composer.phar install --no-progress
|
||||
# php.ini settings
|
||||
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
|
||||
|
||||
# hidden job definition with template for MySQL/MariaDB
|
||||
.job_template_mysql: &job_definition_mysql
|
||||
stage: test
|
||||
@@ -52,13 +37,13 @@ before_script:
|
||||
HZ_TEST_DB_DATABASE: $MYSQL_DATABASE
|
||||
script:
|
||||
# Import hubzilla's DB schema
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$MYSQL_DATABASE"
|
||||
# Show databases and relations/tables of hubzilla's database
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" --skip-ssl "$MYSQL_DATABASE"
|
||||
# Run the actual tests
|
||||
- touch dbfail.out
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- vendor/bin/phpunit -d memory_limit=256M --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
|
||||
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
|
||||
|
||||
@@ -83,7 +68,7 @@ before_script:
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
|
||||
# Run the actual tests
|
||||
- touch dbfail.out
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- vendor/bin/phpunit -d memory_limit=256M --configuration tests/phpunit.xml --no-progress --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
|
||||
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
|
||||
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
|
||||
|
||||
@@ -99,29 +84,55 @@ before_script:
|
||||
paths:
|
||||
- tests/results/
|
||||
|
||||
default:
|
||||
image: php:8.2
|
||||
before_script:
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- apt-get update
|
||||
- apt-get install -yqq libicu-dev libjpeg-dev libpng-dev libpq-dev libyaml-dev libgmp-dev libzip-dev mariadb-client postgresql-client libmagickcore-7.q16-dev libmagickwand-dev unzip zip
|
||||
- pecl install imagick xdebug yaml
|
||||
- docker-php-ext-enable imagick 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
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@
|
||||
<exclude name="Generic.Files.OneClassPerFile.MultipleFound"/>
|
||||
<exclude name="Generic.Files.OneObjectStructurePerFile.MultipleFound"/>
|
||||
<exclude name="Generic.Formatting.SpaceAfterCast.NoSpace"/>
|
||||
|
||||
<exclude name="Generic.Classes.OpeningBraceSameLine.BraceOnNewLine" />
|
||||
<exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed" />
|
||||
<exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine" />
|
||||
</rule>
|
||||
|
||||
<!--
|
||||
|
||||
579
CHANGELOG
579
CHANGELOG
@@ -1,4 +1,578 @@
|
||||
Hubzilla 9.4 (2024-??-??)
|
||||
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
|
||||
|
||||
|
||||
Hubzilla 10.2.2 (2025-04-11)
|
||||
- Cleanup deprecated forum queries, improved performance
|
||||
- Fix zot6 handler returning success allthough Libzot::fetch() did not return anything useful
|
||||
- Fix json encoding of a possibly empty item.target
|
||||
- Fix permalink for forum posts and comments
|
||||
- Fix an obscure delivering issue which could produce duplicate posts
|
||||
- Lazy load profile photos for reactions to reduce server load
|
||||
- Pubcrawl: deal with Update(Tombstone)
|
||||
- Pubcrawl: fix mentions not mapped to "to" in public toplevel posts (regression)
|
||||
|
||||
|
||||
Hubzilla 10.2.1 (2025-03-18)
|
||||
- Fix OWA in cases where Signature is in the REDIRECT_REMOTE_USER field
|
||||
- Fix query in mod sse_bs
|
||||
|
||||
|
||||
Hubzilla 10.2 (2025-03-17)
|
||||
- Allow to send signed requests from the zot_probe tool
|
||||
- Print an error message if OWA fails
|
||||
- Remove possible leading @ before processing webfinger address
|
||||
- Updated debian install script
|
||||
- Calculate observer.baseurl from xchan_url instead of xchan_connurl
|
||||
- Refactor unparse_url() to allow return of a custom field set only and add tests
|
||||
- Slightly improve event object rendering
|
||||
- Update smarty library to version 5 for PHP 8.4 compatibility
|
||||
- Remove vendor/symfony from gitignore file
|
||||
- Update composer libraries
|
||||
- Add contextHistory field to activities and prefer it over context when consuming
|
||||
- Implement highlight button in jot editor
|
||||
- Add test results and PHPStan to gitignore
|
||||
- Update spanish strings
|
||||
- Remove EpubMeta library in favor of a custom solution
|
||||
- Configue gd for jpeg support in CI
|
||||
- Add error message on missing owa auth headers
|
||||
- Add Zotlabs\Tests namespace to autloader in dev
|
||||
- Add dba_pdo::update method
|
||||
- Add dba_pdo::insert method
|
||||
- Rewrite redbasic javascript to remove jquery dependency
|
||||
- Add security policy SECURITY.md
|
||||
|
||||
Bugfixes
|
||||
- Fix notifications for likes on our comments
|
||||
- Fix fullscreen view
|
||||
- Fix boxy scheme text alignment for comments
|
||||
- Fix poll date string to match with the autotime string
|
||||
- Fix owner hash not set correctly when editing a post/comment
|
||||
- Fix an issue where some participants could not post to forums
|
||||
- Fix navbar selector conflict with possible additional navbars when using a cover photo
|
||||
- Fix target and tgt_type not set for sourced rss items if we rewrite them to our own
|
||||
- Fix auto save draft not set correctly
|
||||
- Fix cover height calculation
|
||||
|
||||
Addons
|
||||
- Diaspora: revisit import_diaspora_account()
|
||||
- Pubcrawl: escape quotation marks in ActivityStreams link header
|
||||
- Wiki: fixed wiki_page_list.tpl to use bootstrap class for layout
|
||||
- BBmath: fix orientation for inline math
|
||||
- BBmath: document imagemagick permissions
|
||||
- Pubcrawl: ensure we select the correct hubloc hash when extending recipients list
|
||||
- Msg_footer: do not add footer on edit, also dismiss anything but a create activity
|
||||
- Pubcrawl: refactor activitypub addressing
|
||||
- Wiki: added space to preview panel
|
||||
- Startpage: update help text and some cleanup
|
||||
|
||||
|
||||
Hubzilla 10.0.8 (2025-02-01)
|
||||
- Fix duplicating terms/iconfig in addToCollectionAndSync()
|
||||
- Refactor Daemon/Importdoc for better SQL performance when looking up outdated entries
|
||||
- Tweak SQL in mod sse_bs for possible performance improvements
|
||||
- Fix PHP warnings
|
||||
- Do not run post_local hook on add activities in pubcrawl addon
|
||||
- Do not run post_local hook on add activities in diaspora addon
|
||||
- Remove old rawmsg/fields before storing new rawmsg in pubcrawl addon
|
||||
- Fix retractions in diaspora addon
|
||||
|
||||
|
||||
Hubzilla 10.0.7 (2025-01-22)
|
||||
- Fix ownership check in consume_feed()
|
||||
- Fix toast() if notification contains non-ascii characters
|
||||
- Fix regression in notifications filter
|
||||
|
||||
|
||||
Hubzilla 10.0.6 (2025-01-05)
|
||||
- Fix entries where primary location data is not complete not dismissed early
|
||||
- Fix query to cleanup outdated doc entries called multiple times
|
||||
- Fix query to cleanup outdated doc entries
|
||||
|
||||
|
||||
Hubzilla 10.0.5 (2024-12-29)
|
||||
- Fix another instance of drop_item() not having permission to drop items
|
||||
|
||||
|
||||
Hubzilla 10.0.4 (2024-12-26)
|
||||
- Fix missing argument name
|
||||
|
||||
|
||||
Hubzilla 10.0.3 (2024-12-26)
|
||||
- Fix regression in Daemon/Channel_purge which could cause a possible infinite loop
|
||||
- Fix regression in Daemon/Expire which could cause a infinite loop
|
||||
|
||||
|
||||
Hubzilla 10.0.2 (2024-12-25)
|
||||
- Hotfix comment out Daemon/Expire
|
||||
- Fix zid parameter allowed to override an existing remote login
|
||||
- Slightly improved imagesLoaded()
|
||||
|
||||
|
||||
Hubzilla 10.0.1 (2024-12-22)
|
||||
- Revert removing of openid library
|
||||
- Fix SQL query in Daemon/Importdoc
|
||||
|
||||
|
||||
Hubzilla 10.0 (2024-12-21)
|
||||
- Port updateConvItem() and notifications widget to vanilla javascript
|
||||
- Remove jquery.timeago.js in favor of a native js implementation
|
||||
- Introduce item_forwardable() a function to check if an item should be frowarded
|
||||
- Always set item_delayed flag if we use a custom created date
|
||||
- Add indicators to items in case they are delayed, have an expiration time or commenting is disabled
|
||||
- Introduce relative_time() a new function to calculate the relative time
|
||||
- Refactor mod admin/accounts
|
||||
- Toggle aside if a notification or message is clicked
|
||||
- Add Mailer class to replace z_mail()
|
||||
- Provide a possibility to link to a specific day or month in mod cal via URL fragment e.g. #2024-12-24
|
||||
- Refactor mod magic
|
||||
- Introduce conversation containers a.k.a. FEP-171b
|
||||
- Refactor mod item
|
||||
- Refactor Thumbs\Epubthumb to adapt to new version of EPub meta lib
|
||||
- Remove unused libraries
|
||||
- Bring filed items to mod hq
|
||||
|
||||
Bugfixes
|
||||
- Fix comments on/off toggle
|
||||
- Fix various missing icons after transition from fork-awesome
|
||||
- Fix performance issue in mod pubstream
|
||||
- Fix mails with + in local part rejected
|
||||
- Fix % calculation in mod import_progress
|
||||
- Fix query vars not unset when constructing the server address
|
||||
- Fix can_comment_on_post() logic after introduction of repeats
|
||||
- Fix xchan_query() not including deleted hublocs
|
||||
- Fix allday variable not set when clicking an event or a resource is provided
|
||||
|
||||
Addons
|
||||
- Introduce conversation containers a.k.a. FEP-171b
|
||||
- Cards: fix comments on/off state
|
||||
- Articles: fix comments on/off state
|
||||
- Pubcrawl: fix encoding of stored raw message
|
||||
- Gallery fix zoom icon toggle
|
||||
- Pubcrawl: fix follow to non primary hub location
|
||||
- Pubcrawl: rewrite id host to local host instead of primary host
|
||||
|
||||
|
||||
Hubzilla 9.4.4 (2024-11-06)
|
||||
- Update Norwegian translations
|
||||
- Fix error adding things when multiple profiles not enabled
|
||||
- Port mod thing to use $_GET/$_POST instead of $_REQUEST
|
||||
- Move Norwegian translations from nb-no to nb
|
||||
- Fix intact alernative network hublocs being marked deleted in Libsync::sync_locations()
|
||||
- Fix modals only partly removed when DOM emlement updated via ajax
|
||||
- Add explicit check for channel_address in channel_url()
|
||||
- Fix PHP deprecation warnings in mod setup
|
||||
- Fix PHP warning in Web/HttpMeta
|
||||
- Fix typo in UnitTestCase
|
||||
- Fix missing CSRF token checks in mod account_edit
|
||||
- Fix OCAP tokens only added to images
|
||||
- Fix unescaped zid parameter
|
||||
- Fix wrong date format in published date in update question activities
|
||||
- Fix include for en TOS page
|
||||
- Fix query in copy_of_pubitem() returning duplicate items
|
||||
- Fix edit button not clickable if below right aside when viewing webpages
|
||||
- Fix rendering of category tags icons in the editor
|
||||
- Fix regex to detect URLs in cleanup_bbcode
|
||||
- Fix duplicate posts from forum clones
|
||||
- Fix follow to non primary hub location in pubcrawl addon
|
||||
- Fix id host not rewritten to local host in pubcrawl addon
|
||||
- Fix regression when manually fetching items in pubcrawl addon
|
||||
|
||||
|
||||
Hubzilla 9.4.3 (2024-10-10)
|
||||
- Discard Add/Remove activities (Hubzilla 10 and (streams) compatibility)
|
||||
- Fix HQ channel activities icons
|
||||
- Fix saved search icons
|
||||
|
||||
|
||||
Hubzilla 9.4.2 (2024-10-04)
|
||||
- Indicate reacted state via icon color (community wish)
|
||||
- Fix modal backdrop not removed when reacting from the modal
|
||||
- Fix missing handle icon in mod pdledit_gui
|
||||
|
||||
|
||||
Hubzilla 9.4.1 (2024-10-02)
|
||||
- Various fixes for the help module
|
||||
- Update smarty library via composer
|
||||
- Fix URLs replaced with bbcode in codeblocks if markdown enabled
|
||||
- Fix unable to move multiple files when using postgresql DB backend
|
||||
- Adjust icon for post app
|
||||
- Fix check for while loop in wiki addon
|
||||
|
||||
|
||||
Hubzilla 9.4 (2024-09-25)
|
||||
- If we got an ocap token try to authenticate with it first
|
||||
- Hide comment titles
|
||||
- Adjust fix_attached_permissions() to only add the token if we got one
|
||||
@@ -23,9 +597,12 @@ Hubzilla 9.4 (2024-??-??)
|
||||
- Code cleanup and remove some unused/deprecated functions
|
||||
|
||||
Bugfixes
|
||||
- Fix broken help pages search
|
||||
- Fix notes app not displaying anything - issue #1865
|
||||
|
||||
Addons
|
||||
- Cards: fix decoding issue when editing and minor cleanup
|
||||
- Articles: fix decoding issue when editing and minor cleanup
|
||||
- Wiki: fix markdown content not unescaped when undoing history - issue #1864
|
||||
- Gallery: update to photoswipe 5.4.4
|
||||
- Openstreemap: streamline location rendering
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
"air" is a branch name for revision of Account-Invite-Register at the Hubzilla project
|
||||
|
||||
Invite:
|
||||
* Rewritten and now language template driven
|
||||
* Selectable templates for the invite mails
|
||||
* Invitor may add personal notes in the mailtext
|
||||
+ Invite codes are bound to the recipients email address
|
||||
* Invite mod never more creates accounts
|
||||
* new db scheme for table register
|
||||
* existing register table will be migrated to the new schema even when detected at runtime
|
||||
* Bugfix: creating invite codes when admin only calls Invite w/o any further action
|
||||
* account library revision also together with invite mod
|
||||
* Depending on config: Users may send invitations also
|
||||
* Invitations expires, controlled by the invitor
|
||||
* Changed and new configs:
|
||||
* * invitation_only As usual before
|
||||
* * invitation_also Beside other registration policies, invitations may be used also
|
||||
* * invitation_max_per_day defaults 50, may be changed in adminUI admin>site
|
||||
* * invitation_max_per_user defaults 4
|
||||
* Requirements:
|
||||
* * Addon language has to be installed
|
||||
|
||||
Register:
|
||||
* Register panel (form) and js interaction changed
|
||||
* Unused registrations expire
|
||||
* Depending on config, anonymous registrations (w/o email) are supported
|
||||
* :... dont't panic, that may let grow security
|
||||
* Even anonymous users have to confirm their registration
|
||||
* Registrations may be enabled / disabled time driven for each day in the week (dudy)
|
||||
* Unsoliced registration floods may be blocked
|
||||
* Limited registrations from one single source ip
|
||||
* Using one additional log file, to easy interfare with f2b
|
||||
|
||||
Account:
|
||||
* An user account always becomes created only if all depending conditions are satisfied
|
||||
* AdminUI for site configuration, accounts and registrations enhancements
|
||||
* Still untouched, but accountUI needs enhanced async control in case for mass delete
|
||||
with deep level of recursion cascade of the dependencies (channels etc). An open TODO
|
||||
since years for instances with many much users and channels.
|
||||
|
||||
History:
|
||||
2020.03 Hubzilla Prod version 4.6 (master branch) of hubzilla/core was the base for AIR
|
||||
that was assigned Version 4.6.2 at sn/core
|
||||
2021.02 Hubzilla Prod version 5.2.1 (master branch) of hubzilla/core was new base for AIR
|
||||
that was assigned version 5.2.2 at sn/core (air.5)
|
||||
plus adjustment of hubzilla 5.2.2 (master) to sn/core (air.5) version 5.2.9
|
||||
|
||||
|
||||
31
SECURITY.md
Normal file
31
SECURITY.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Hubzilla Security Policy
|
||||
|
||||
The [Hubzilla] Project takes security, privacy and user control over personal data seriously. We ask that any security issues be disclosed to us in a responsible manner to allow us time to remediate the issues, and site administrators time to upgrade before information about the issue is made public.
|
||||
|
||||
This document outlines security procedures and policies for the Hubzilla project. It covers the following components:
|
||||
|
||||
* The Hubzilla core repository: https://framagit.org/hubzilla/core
|
||||
* The official addon repository: https://framagit.org/hubzilla/addons
|
||||
* The official themes repository: https://framagit.org/hubzilla/themes
|
||||
* The official widgets repository: https://framagit.org/hubzilla/widgets
|
||||
|
||||
## Coordinated Disclosure Guidelines
|
||||
|
||||
We are committed to working with security researchers to verify, reproduce, and respond to legitimate reported vulnerabilities. You can help us by following these simple guidelines:
|
||||
|
||||
* Submit suspected vulnerabilities by email to `security@hubzilla.org`, or as a confidential issue in the relevant repository listed above.
|
||||
* Provide clear instructions on how to reproduce the issue, and if possible, a minimal Proof of Concept (PoC) exploit.
|
||||
* We will acknowledge your submission as soon as we can, and will keep you updated as it is being processed. We may ask for more information, or clarifications about the issue or the steps to reproduce it during this time.
|
||||
* We will assign a CVE to the issue once it is confirmed.
|
||||
* We will do our best to fix the issue as soon as we can after it has been confirmed. We request that information about the vulnerability or details about how to exploit it is not disclosed to other parties until after the fix is released and some time has passed, to allow site administrators to upgrade. We will normally make the CVE public one month after a fix has been released. (This grace period can differ based on severity, and can be negotiated.)
|
||||
* Please perform all tests against a local instance of the software, and refrain from running any Denial of Service or automated testing tools against public hubs or the project managers (and their partners') infrastructure.
|
||||
* If the issue belongs to a third party module that we depend on, we may help with reporting it upstream if the submitter wants us to.
|
||||
|
||||
## Comments on this Policy
|
||||
|
||||
We welcome comments and suggestions for improving this policy. You can reach us at:
|
||||
|
||||
* Our ticketing system: https://framagit.org/hubzilla/core/-/issues
|
||||
* By sending us an email at `security@hubzilla.org`.
|
||||
|
||||
[Hubzilla]: https://hubzilla.org
|
||||
@@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
776
Zotlabs/ActivityStreams/ASObject.php
Normal file
776
Zotlabs/ActivityStreams/ASObject.php
Normal file
@@ -0,0 +1,776 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
|
||||
use Zotlabs\Lib\BaseObject;
|
||||
|
||||
class ASObject extends BaseObject
|
||||
{
|
||||
public $id;
|
||||
public $type;
|
||||
public $attachment;
|
||||
public $attributedTo;
|
||||
public $audience;
|
||||
public $content;
|
||||
public $context;
|
||||
public $name;
|
||||
public $endTime;
|
||||
public $generator;
|
||||
public $icon;
|
||||
public $image;
|
||||
public $inReplyTo;
|
||||
public $location;
|
||||
public $preview;
|
||||
public $published;
|
||||
public $replies;
|
||||
public $startTime;
|
||||
public $summary;
|
||||
public $tag;
|
||||
public $updated;
|
||||
public $url;
|
||||
public $to;
|
||||
public $bto;
|
||||
public $cc;
|
||||
public $bcc;
|
||||
public $mediaType;
|
||||
public $duration;
|
||||
public $source;
|
||||
|
||||
|
||||
// Extension properties
|
||||
|
||||
public $signature;
|
||||
public $proof;
|
||||
public $sensitive;
|
||||
public $replyTo;
|
||||
public $wall;
|
||||
public $isContainedConversation;
|
||||
public $expires;
|
||||
public $canReply;
|
||||
public $canSearch;
|
||||
public $directMessage;
|
||||
public $commentPolicy;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDirectMessage()
|
||||
{
|
||||
return $this->directMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $directMessage
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setDirectMessage($directMessage)
|
||||
{
|
||||
$this->directMessage = $directMessage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSignature()
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $signature
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setSignature($signature)
|
||||
{
|
||||
$this->signature = $signature;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getProof()
|
||||
{
|
||||
return $this->proof;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $proof
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setProof($proof)
|
||||
{
|
||||
$this->proof = $proof;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSensitive()
|
||||
{
|
||||
return $this->sensitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $sensitive
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setSensitive($sensitive)
|
||||
{
|
||||
$this->sensitive = $sensitive;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getReplyTo()
|
||||
{
|
||||
return $this->replyTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $replyTo
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setReplyTo($replyTo)
|
||||
{
|
||||
$this->replyTo = $replyTo;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getWall()
|
||||
{
|
||||
return $this->wall;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $wall
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setWall($wall)
|
||||
{
|
||||
$this->wall = $wall;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIsContainedConversation()
|
||||
{
|
||||
return $this->isContainedConversation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $isContainedConversation
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setIsContainedConversation($isContainedConversation)
|
||||
{
|
||||
$this->isContainedConversation = $isContainedConversation;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getExpires()
|
||||
{
|
||||
return $this->expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $expires
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setExpires($expires)
|
||||
{
|
||||
$this->expires = $expires;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCanReply()
|
||||
{
|
||||
return $this->canReply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $canReply
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setCanReply($canReply)
|
||||
{
|
||||
$this->canReply = $canReply;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCanSearch()
|
||||
{
|
||||
return $this->canSearch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $canSearch
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setCanSearch($canSearch)
|
||||
{
|
||||
$this->canSearch = $canSearch;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCommentPolicy()
|
||||
{
|
||||
return $this->commentPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $commentPolicy
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setCommentPolicy($commentPolicy)
|
||||
{
|
||||
$this->commentPolicy = $commentPolicy;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $type
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttachment()
|
||||
{
|
||||
return $this->attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $attachment
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setAttachment($attachment)
|
||||
{
|
||||
$this->attachment = $attachment;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttributedTo()
|
||||
{
|
||||
return $this->attributedTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $attributedTo
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setAttributedTo($attributedTo)
|
||||
{
|
||||
$this->attributedTo = $attributedTo;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAudience()
|
||||
{
|
||||
return $this->audience;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $audience
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setAudience($audience)
|
||||
{
|
||||
$this->audience = $audience;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $content
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->content = $content;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getContext()
|
||||
{
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $context
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setContext($context)
|
||||
{
|
||||
$this->context = $context;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $name
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEndTime()
|
||||
{
|
||||
return $this->endTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $endTime
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setEndTime($endTime)
|
||||
{
|
||||
$this->endTime = $endTime;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getGenerator()
|
||||
{
|
||||
return $this->generator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $generator
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setGenerator($generator)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIcon()
|
||||
{
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $icon
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setIcon($icon)
|
||||
{
|
||||
$this->icon = $icon;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getImage()
|
||||
{
|
||||
return $this->image;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $image
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setImage($image)
|
||||
{
|
||||
$this->image = $image;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getInReplyTo()
|
||||
{
|
||||
return $this->inReplyTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $inReplyTo
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setInReplyTo($inReplyTo)
|
||||
{
|
||||
$this->inReplyTo = $inReplyTo;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLocation()
|
||||
{
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $location
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setLocation($location)
|
||||
{
|
||||
$this->location = $location;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPreview()
|
||||
{
|
||||
return $this->preview;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $preview
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setPreview($preview)
|
||||
{
|
||||
$this->preview = $preview;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublished()
|
||||
{
|
||||
return $this->published;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $published
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setPublished($published)
|
||||
{
|
||||
$this->published = $published;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getReplies()
|
||||
{
|
||||
return $this->replies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $replies
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setReplies($replies)
|
||||
{
|
||||
$this->replies = $replies;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getStartTime()
|
||||
{
|
||||
return $this->startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $startTime
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setStartTime($startTime)
|
||||
{
|
||||
$this->startTime = $startTime;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSummary()
|
||||
{
|
||||
return $this->summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $summary
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setSummary($summary)
|
||||
{
|
||||
$this->summary = $summary;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $tag
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setTag($tag)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUpdated()
|
||||
{
|
||||
return $this->updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $updated
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setUpdated($updated)
|
||||
{
|
||||
$this->updated = $updated;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $url
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setUrl($url)
|
||||
{
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTo()
|
||||
{
|
||||
return $this->to;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $to
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setTo($to)
|
||||
{
|
||||
$this->to = $to;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBto()
|
||||
{
|
||||
return $this->bto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $bto
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setBto($bto)
|
||||
{
|
||||
$this->bto = $bto;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCc()
|
||||
{
|
||||
return $this->cc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $cc
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setCc($cc)
|
||||
{
|
||||
$this->cc = $cc;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBcc()
|
||||
{
|
||||
return $this->bcc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $bcc
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setBcc($bcc)
|
||||
{
|
||||
$this->bcc = $bcc;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMediaType()
|
||||
{
|
||||
return $this->mediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $mediaType
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setMediaType($mediaType)
|
||||
{
|
||||
$this->mediaType = $mediaType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDuration()
|
||||
{
|
||||
return $this->duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $duration
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setDuration($duration)
|
||||
{
|
||||
$this->duration = $duration;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSource()
|
||||
{
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $source
|
||||
* @return ASObject
|
||||
*/
|
||||
public function setSource($source)
|
||||
{
|
||||
$this->source = $source;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
122
Zotlabs/ActivityStreams/Activity.php
Normal file
122
Zotlabs/ActivityStreams/Activity.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Activity extends ASObject
|
||||
{
|
||||
public $actor;
|
||||
public $object;
|
||||
public $target;
|
||||
public $result;
|
||||
public $origin;
|
||||
public $instrument;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getActor()
|
||||
{
|
||||
return $this->actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $actor
|
||||
* @return Activity
|
||||
*/
|
||||
public function setActor($actor)
|
||||
{
|
||||
$this->actor = $actor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getObject()
|
||||
{
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $object
|
||||
* @return Activity
|
||||
*/
|
||||
public function setObject($object)
|
||||
{
|
||||
$this->object = $object;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTarget()
|
||||
{
|
||||
return $this->target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $target
|
||||
* @return Activity
|
||||
*/
|
||||
public function setTarget($target)
|
||||
{
|
||||
$this->target = $target;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResult()
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $result
|
||||
* @return Activity
|
||||
*/
|
||||
public function setResult($result)
|
||||
{
|
||||
$this->result = $result;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOrigin()
|
||||
{
|
||||
return $this->origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $origin
|
||||
* @return Activity
|
||||
*/
|
||||
public function setOrigin($origin)
|
||||
{
|
||||
$this->origin = $origin;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getInstrument()
|
||||
{
|
||||
return $this->instrument;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $instrument
|
||||
* @return Activity
|
||||
*/
|
||||
public function setInstrument($instrument)
|
||||
{
|
||||
$this->instrument = $instrument;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
428
Zotlabs/ActivityStreams/Actor.php
Normal file
428
Zotlabs/ActivityStreams/Actor.php
Normal file
@@ -0,0 +1,428 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Actor extends ASObject
|
||||
{
|
||||
public $inbox;
|
||||
public $outbox;
|
||||
public $followers;
|
||||
public $following;
|
||||
public $permissions; /* extension property */
|
||||
public $endpoints;
|
||||
public $publicKey;
|
||||
public $preferredUsername;
|
||||
public $alsoKnownAs;
|
||||
|
||||
// Extension properties
|
||||
|
||||
public $movedTo;
|
||||
public $copiedTo;
|
||||
public $discoverable;
|
||||
public $manuallyApprovesFollowers;
|
||||
public $webfinger;
|
||||
public $canSearch;
|
||||
public $indexable;
|
||||
public $assertionMethod;
|
||||
public $gateways;
|
||||
public $openwebauth;
|
||||
public $authredirect;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAlsoKnownAs()
|
||||
{
|
||||
return $this->alsoKnownAs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $alsoKnownAs
|
||||
* @return Actor
|
||||
*/
|
||||
public function setAlsoKnownAs($alsoKnownAs)
|
||||
{
|
||||
$this->alsoKnownAs = $alsoKnownAs;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMovedTo()
|
||||
{
|
||||
return $this->movedTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCopiedTo()
|
||||
{
|
||||
return $this->copiedTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $copiedTo
|
||||
* @return Actor
|
||||
*/
|
||||
public function setCopiedTo($copiedTo)
|
||||
{
|
||||
$this->copiedTo = $copiedTo;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $movedTo
|
||||
* @return Actor
|
||||
*/
|
||||
public function setMovedTo($movedTo)
|
||||
{
|
||||
$this->movedTo = $movedTo;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDiscoverable()
|
||||
{
|
||||
return $this->discoverable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $discoverable
|
||||
* @return Actor
|
||||
*/
|
||||
public function setDiscoverable($discoverable)
|
||||
{
|
||||
$this->discoverable = $discoverable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getManuallyApprovesFollowers()
|
||||
{
|
||||
return $this->manuallyApprovesFollowers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $manuallyApprovesFollowers
|
||||
* @return Actor
|
||||
*/
|
||||
public function setManuallyApprovesFollowers($manuallyApprovesFollowers)
|
||||
{
|
||||
$this->manuallyApprovesFollowers = $manuallyApprovesFollowers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPreferredUsername()
|
||||
{
|
||||
return $this->preferredUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $preferredUsername
|
||||
* @return Actor
|
||||
*/
|
||||
public function setPreferredUsername($preferredUsername)
|
||||
{
|
||||
$this->preferredUsername = $preferredUsername;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return Actor
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $type
|
||||
* @return Actor
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getInbox()
|
||||
{
|
||||
return $this->inbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $inbox
|
||||
* @return Actor
|
||||
*/
|
||||
public function setInbox($inbox)
|
||||
{
|
||||
$this->inbox = $inbox;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOutbox()
|
||||
{
|
||||
return $this->outbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $outbox
|
||||
* @return Actor
|
||||
*/
|
||||
public function setOutbox($outbox)
|
||||
{
|
||||
$this->outbox = $outbox;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFollowers()
|
||||
{
|
||||
return $this->followers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $followers
|
||||
* @return Actor
|
||||
*/
|
||||
public function setFollowers($followers)
|
||||
{
|
||||
$this->followers = $followers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFollowing()
|
||||
{
|
||||
return $this->following;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $following
|
||||
* @return Actor
|
||||
*/
|
||||
public function setFollowing($following)
|
||||
{
|
||||
$this->following = $following;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEndpoints()
|
||||
{
|
||||
return $this->endpoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $endpoints
|
||||
* @return Actor
|
||||
*/
|
||||
public function setEndpoints($endpoints)
|
||||
{
|
||||
$this->endpoints = $endpoints;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKey()
|
||||
{
|
||||
return $this->publicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $publicKey
|
||||
* @return Actor
|
||||
*/
|
||||
public function setPublicKey($publicKey)
|
||||
{
|
||||
$this->publicKey = $publicKey;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getWebfinger()
|
||||
{
|
||||
return $this->webfinger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $webfinger
|
||||
* @return Actor
|
||||
*/
|
||||
public function setWebfinger($webfinger)
|
||||
{
|
||||
$this->webfinger = $webfinger;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCanSearch()
|
||||
{
|
||||
return $this->canSearch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $canSearch
|
||||
* @return Actor
|
||||
*/
|
||||
public function setCanSearch($canSearch)
|
||||
{
|
||||
$this->canSearch = $canSearch;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIndexable()
|
||||
{
|
||||
return $this->indexable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $indexable
|
||||
* @return Actor
|
||||
*/
|
||||
public function setIndexable($indexable)
|
||||
{
|
||||
$this->indexable = $indexable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAssertionMethod()
|
||||
{
|
||||
return $this->assertionMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $assertionMethod
|
||||
* @return Actor
|
||||
*/
|
||||
public function setAssertionMethod($assertionMethod)
|
||||
{
|
||||
$this->assertionMethod = $assertionMethod;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getGateways()
|
||||
{
|
||||
return $this->gateways;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $gateways
|
||||
* @return Actor
|
||||
*/
|
||||
public function setGateways($gateways)
|
||||
{
|
||||
$this->gateways = $gateways;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPermissions()
|
||||
{
|
||||
return $this->permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $permissions
|
||||
* @return Actor
|
||||
*/
|
||||
public function setPermissions($permissions)
|
||||
{
|
||||
$this->permissions = $permissions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOpenwebauth()
|
||||
{
|
||||
return $this->openwebauth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $openwebauth
|
||||
* @return Actor
|
||||
*/
|
||||
public function setOpenwebauth($openwebauth)
|
||||
{
|
||||
$this->openwebauth = $openwebauth;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAuthredirect()
|
||||
{
|
||||
return $this->authredirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $authredirect
|
||||
* @return Actor
|
||||
*/
|
||||
public function setAuthredirect($authredirect)
|
||||
{
|
||||
$this->authredirect = $authredirect;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
87
Zotlabs/ActivityStreams/AssertionMethod.php
Normal file
87
Zotlabs/ActivityStreams/AssertionMethod.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class AssertionMethod extends ASObject
|
||||
{
|
||||
public $id;
|
||||
public $type;
|
||||
public $controller;
|
||||
public $publicKeyMultibase;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return AssertionMethod
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $type
|
||||
* @return AssertionMethod
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getController()
|
||||
{
|
||||
return $this->controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $controller
|
||||
* @return AssertionMethod
|
||||
*/
|
||||
public function setController($controller)
|
||||
{
|
||||
$this->controller = $controller;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKeyMultibase()
|
||||
{
|
||||
return $this->publicKeyMultibase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $publicKeyMultibase
|
||||
* @return AssertionMethod
|
||||
*/
|
||||
public function setPublicKeyMultibase($publicKeyMultibase)
|
||||
{
|
||||
$this->publicKeyMultibase = $publicKeyMultibase;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
124
Zotlabs/ActivityStreams/Collection.php
Normal file
124
Zotlabs/ActivityStreams/Collection.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Collection extends ASObject
|
||||
{
|
||||
public int $totalItems;
|
||||
public string $current;
|
||||
public string $first;
|
||||
public string $last;
|
||||
public array $items;
|
||||
|
||||
public mixed $collectionOf;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalItems(): int
|
||||
{
|
||||
return $this->totalItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $totalItems
|
||||
* @return Collection
|
||||
*/
|
||||
public function setTotalItems(mixed $totalItems): static
|
||||
{
|
||||
$this->totalItems = $totalItems;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrent(): string
|
||||
{
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $current
|
||||
* @return Collection
|
||||
*/
|
||||
public function setCurrent(mixed $current): static
|
||||
{
|
||||
$this->current = $current;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFirst(): string
|
||||
{
|
||||
return $this->first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $first
|
||||
* @return Collection
|
||||
*/
|
||||
public function setFirst(mixed $first): static
|
||||
{
|
||||
$this->first = $first;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLast(): string
|
||||
{
|
||||
return $this->last;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $last
|
||||
* @return Collection
|
||||
*/
|
||||
public function setLast(mixed $last): static
|
||||
{
|
||||
$this->last = $last;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getItems(): array
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $items
|
||||
* @return Collection
|
||||
*/
|
||||
public function setItems(mixed $items): static
|
||||
{
|
||||
$this->items = $items;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCollectionOf(): mixed
|
||||
{
|
||||
return $this->collectionOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $collectionOf
|
||||
* @return Collection
|
||||
*/
|
||||
public function setCollectionOf(mixed $collectionOf): static
|
||||
{
|
||||
$this->collectionOf = $collectionOf;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
73
Zotlabs/ActivityStreams/CollectionPage.php
Normal file
73
Zotlabs/ActivityStreams/CollectionPage.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class CollectionPage extends Collection
|
||||
{
|
||||
public $partOf;
|
||||
public $next;
|
||||
public $prev;
|
||||
|
||||
// startIndex only applies for OrderedCollectionPage. See
|
||||
// https://www.w3.org/ns/activitystreams#OrderedCollectionPage
|
||||
// It is provided here to avoid multiple inheritance
|
||||
|
||||
public $startIndex;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPartOf()
|
||||
{
|
||||
return $this->partOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $partOf
|
||||
* @return CollectionPage
|
||||
*/
|
||||
public function setPartOf($partOf)
|
||||
{
|
||||
$this->partOf = $partOf;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getNext()
|
||||
{
|
||||
return $this->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $next
|
||||
* @return CollectionPage
|
||||
*/
|
||||
public function setNext($next)
|
||||
{
|
||||
$this->next = $next;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPrev()
|
||||
{
|
||||
return $this->prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $prev
|
||||
* @return CollectionPage
|
||||
*/
|
||||
public function setPrev($prev)
|
||||
{
|
||||
$this->prev = $prev;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
104
Zotlabs/ActivityStreams/IntransitiveActivity.php
Normal file
104
Zotlabs/ActivityStreams/IntransitiveActivity.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
|
||||
class IntransitiveActivity extends ASObject
|
||||
{
|
||||
public $actor;
|
||||
public $target;
|
||||
public $result;
|
||||
public $origin;
|
||||
public $instrument;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getActor()
|
||||
{
|
||||
return $this->actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $actor
|
||||
* @return IntransitiveActivity
|
||||
*/
|
||||
public function setActor($actor)
|
||||
{
|
||||
$this->actor = $actor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTarget()
|
||||
{
|
||||
return $this->target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $target
|
||||
* @return IntransitiveActivity
|
||||
*/
|
||||
public function setTarget($target)
|
||||
{
|
||||
$this->target = $target;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResult()
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $result
|
||||
* @return IntransitiveActivity
|
||||
*/
|
||||
public function setResult($result)
|
||||
{
|
||||
$this->result = $result;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOrigin()
|
||||
{
|
||||
return $this->origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $origin
|
||||
* @return IntransitiveActivity
|
||||
*/
|
||||
public function setOrigin($origin)
|
||||
{
|
||||
$this->origin = $origin;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getInstrument()
|
||||
{
|
||||
return $this->instrument;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $instrument
|
||||
* @return IntransitiveActivity
|
||||
*/
|
||||
public function setInstrument($instrument)
|
||||
{
|
||||
$this->instrument = $instrument;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
183
Zotlabs/ActivityStreams/Link.php
Normal file
183
Zotlabs/ActivityStreams/Link.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
use Zotlabs\Lib\BaseObject;
|
||||
|
||||
class Link extends BaseObject
|
||||
{
|
||||
public $type;
|
||||
public $href;
|
||||
public $rel;
|
||||
public $mediaType;
|
||||
public $name;
|
||||
public $hreflang;
|
||||
public $height;
|
||||
public $width;
|
||||
public $preview;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $type
|
||||
* @return Link
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHref()
|
||||
{
|
||||
return $this->href;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $href
|
||||
* @return Link
|
||||
*/
|
||||
public function setHref($href)
|
||||
{
|
||||
$this->href = $href;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRel()
|
||||
{
|
||||
return $this->rel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $rel
|
||||
* @return Link
|
||||
*/
|
||||
public function setRel($rel)
|
||||
{
|
||||
$this->rel = $rel;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMediaType()
|
||||
{
|
||||
return $this->mediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $mediaType
|
||||
* @return Link
|
||||
*/
|
||||
public function setMediaType($mediaType)
|
||||
{
|
||||
$this->mediaType = $mediaType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $name
|
||||
* @return Link
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHreflang()
|
||||
{
|
||||
return $this->hreflang;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $hreflang
|
||||
* @return Link
|
||||
*/
|
||||
public function setHreflang($hreflang)
|
||||
{
|
||||
$this->hreflang = $hreflang;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHeight()
|
||||
{
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $height
|
||||
* @return Link
|
||||
*/
|
||||
public function setHeight($height)
|
||||
{
|
||||
$this->height = $height;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getWidth()
|
||||
{
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $width
|
||||
* @return Link
|
||||
*/
|
||||
public function setWidth($width)
|
||||
{
|
||||
$this->width = $width;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPreview()
|
||||
{
|
||||
return $this->preview;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $preview
|
||||
* @return Link
|
||||
*/
|
||||
public function setPreview($preview)
|
||||
{
|
||||
$this->preview = $preview;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
8
Zotlabs/ActivityStreams/OrderedCollection.php
Normal file
8
Zotlabs/ActivityStreams/OrderedCollection.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class OrderedCollection extends Collection
|
||||
{
|
||||
|
||||
}
|
||||
92
Zotlabs/ActivityStreams/OrderedCollectionPage.php
Normal file
92
Zotlabs/ActivityStreams/OrderedCollectionPage.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
/**
|
||||
* According to the specification, OrderedCollectionPage extends
|
||||
* both OrderedCollection and CollectionPage, but PHP is still a bit awkward
|
||||
* when it comes to multiple inheritance. Rather than try and do this with
|
||||
* traits, we'll just include the CollectionPage elements here - as this only
|
||||
* consists of three properties.
|
||||
*/
|
||||
|
||||
class OrderedCollectionPage extends OrderedCollection
|
||||
{
|
||||
public $partOf;
|
||||
public $next;
|
||||
public $prev;
|
||||
public $startIndex;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPartOf()
|
||||
{
|
||||
return $this->partOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $partOf
|
||||
* @return OrderedCollectionPage
|
||||
*/
|
||||
public function setPartOf($partOf)
|
||||
{
|
||||
$this->partOf = $partOf;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getNext()
|
||||
{
|
||||
return $this->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $next
|
||||
* @return OrderedCollectionPage
|
||||
*/
|
||||
public function setNext($next)
|
||||
{
|
||||
$this->next = $next;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPrev()
|
||||
{
|
||||
return $this->prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $prev
|
||||
* @return OrderedCollectionPage
|
||||
*/
|
||||
public function setPrev($prev)
|
||||
{
|
||||
$this->prev = $prev;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getStartIndex()
|
||||
{
|
||||
return $this->startIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $startIndex
|
||||
* @return OrderedCollectionPage
|
||||
*/
|
||||
public function setStartIndex($startIndex)
|
||||
{
|
||||
$this->startIndex = $startIndex;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
125
Zotlabs/ActivityStreams/Place.php
Normal file
125
Zotlabs/ActivityStreams/Place.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Place extends ASObject
|
||||
{
|
||||
|
||||
public $accuracy;
|
||||
public $altitude;
|
||||
public $latitude;
|
||||
public $longitude;
|
||||
public $radius;
|
||||
public $units;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAccuracy()
|
||||
{
|
||||
return $this->accuracy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $accuracy
|
||||
* @return Place
|
||||
*/
|
||||
public function setAccuracy($accuracy)
|
||||
{
|
||||
$this->accuracy = $accuracy;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAltitude()
|
||||
{
|
||||
return $this->altitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $altitude
|
||||
* @return Place
|
||||
*/
|
||||
public function setAltitude($altitude)
|
||||
{
|
||||
$this->altitude = $altitude;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLatitude()
|
||||
{
|
||||
return $this->latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $latitude
|
||||
* @return Place
|
||||
*/
|
||||
public function setLatitude($latitude)
|
||||
{
|
||||
$this->latitude = $latitude;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLongitude()
|
||||
{
|
||||
return $this->longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $longitude
|
||||
* @return Place
|
||||
*/
|
||||
public function setLongitude($longitude)
|
||||
{
|
||||
$this->longitude = $longitude;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRadius()
|
||||
{
|
||||
return $this->radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $radius
|
||||
* @return Place
|
||||
*/
|
||||
public function setRadius($radius)
|
||||
{
|
||||
$this->radius = $radius;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUnits()
|
||||
{
|
||||
return $this->units;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $units
|
||||
* @return Place
|
||||
*/
|
||||
public function setUnits($units)
|
||||
{
|
||||
$this->units = $units;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
29
Zotlabs/ActivityStreams/Profile.php
Normal file
29
Zotlabs/ActivityStreams/Profile.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Profile extends ASObject
|
||||
{
|
||||
|
||||
public $describes;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDescribes()
|
||||
{
|
||||
return $this->describes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $describes
|
||||
* @return Profile
|
||||
*/
|
||||
public function setDescribes($describes)
|
||||
{
|
||||
$this->describes = $describes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
68
Zotlabs/ActivityStreams/PublicKey.php
Normal file
68
Zotlabs/ActivityStreams/PublicKey.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class PublicKey extends ASObject
|
||||
{
|
||||
public $owner;
|
||||
public $signatureAlgorithm;
|
||||
public $publicKeyPem;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOwner()
|
||||
{
|
||||
return $this->owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $owner
|
||||
* @return PublicKey
|
||||
*/
|
||||
public function setOwner($owner)
|
||||
{
|
||||
$this->owner = $owner;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSignatureAlgorithm()
|
||||
{
|
||||
return $this->signatureAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $signatureAlgorithm
|
||||
* @return PublicKey
|
||||
*/
|
||||
public function setSignatureAlgorithm($signatureAlgorithm)
|
||||
{
|
||||
$this->signatureAlgorithm = $signatureAlgorithm;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKeyPem()
|
||||
{
|
||||
return $this->publicKeyPem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $publicKeyPem
|
||||
* @return PublicKey
|
||||
*/
|
||||
public function setPublicKeyPem($publicKeyPem)
|
||||
{
|
||||
$this->publicKeyPem = $publicKeyPem;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
67
Zotlabs/ActivityStreams/Question.php
Normal file
67
Zotlabs/ActivityStreams/Question.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Question extends ASObject
|
||||
{
|
||||
public $oneOf;
|
||||
public $anyOf;
|
||||
public $closed;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOneOf()
|
||||
{
|
||||
return $this->oneOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oneOf
|
||||
* @return Question
|
||||
*/
|
||||
public function setOneOf($oneOf)
|
||||
{
|
||||
$this->oneOf = $oneOf;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAnyOf()
|
||||
{
|
||||
return $this->anyOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $anyOf
|
||||
* @return Question
|
||||
*/
|
||||
public function setAnyOf($anyOf)
|
||||
{
|
||||
$this->anyOf = $anyOf;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getClosed()
|
||||
{
|
||||
return $this->closed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $closed
|
||||
* @return Question
|
||||
*/
|
||||
public function setClosed($closed)
|
||||
{
|
||||
$this->closed = $closed;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
67
Zotlabs/ActivityStreams/Relationship.php
Normal file
67
Zotlabs/ActivityStreams/Relationship.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Relationship extends ASObject
|
||||
{
|
||||
public $subject;
|
||||
public $object;
|
||||
public $relationship;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSubject()
|
||||
{
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $subject
|
||||
* @return Relationship
|
||||
*/
|
||||
public function setSubject($subject)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getObject()
|
||||
{
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $object
|
||||
* @return Relationship
|
||||
*/
|
||||
public function setObject($object)
|
||||
{
|
||||
$this->object = $object;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRelationship()
|
||||
{
|
||||
return $this->relationship;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $relationship
|
||||
* @return Relationship
|
||||
*/
|
||||
public function setRelationship($relationship)
|
||||
{
|
||||
$this->relationship = $relationship;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
65
Zotlabs/ActivityStreams/Signature.php
Normal file
65
Zotlabs/ActivityStreams/Signature.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Signature extends ASObject
|
||||
{
|
||||
public $nonce;
|
||||
public $creator;
|
||||
public $signatureValue;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCreator()
|
||||
{
|
||||
return $this->creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $creator
|
||||
* @return Signature
|
||||
*/
|
||||
public function setCreator($creator)
|
||||
{
|
||||
$this->creator = $creator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSignatureValue()
|
||||
{
|
||||
return $this->signatureValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $signatureValue
|
||||
* @return Signature
|
||||
*/
|
||||
public function setSignatureValue($signatureValue)
|
||||
{
|
||||
$this->signatureValue = $signatureValue;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getNonce()
|
||||
{
|
||||
return $this->nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $nonce
|
||||
* @return Signature
|
||||
*/
|
||||
public function setNonce($nonce)
|
||||
{
|
||||
$this->nonce = $nonce;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
48
Zotlabs/ActivityStreams/Tombstone.php
Normal file
48
Zotlabs/ActivityStreams/Tombstone.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class Tombstone extends ASObject
|
||||
{
|
||||
public $formerType;
|
||||
public $deleted;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFormerType()
|
||||
{
|
||||
return $this->formerType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $formerType
|
||||
* @return Tombstone
|
||||
*/
|
||||
public function setFormerType($formerType)
|
||||
{
|
||||
$this->formerType = $formerType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDeleted()
|
||||
{
|
||||
return $this->deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $deleted
|
||||
* @return Tombstone
|
||||
*/
|
||||
public function setDeleted($deleted)
|
||||
{
|
||||
$this->deleted = $deleted;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
8
Zotlabs/ActivityStreams/UnhandledElementException.php
Normal file
8
Zotlabs/ActivityStreams/UnhandledElementException.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\ActivityStreams;
|
||||
|
||||
class UnhandledElementException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -6,23 +6,28 @@ class Cache_embeds {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
if(! $argc == 2)
|
||||
if(!$argc == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
$c = q("select body from item where id = %d ",
|
||||
dbesc(intval($argv[1]))
|
||||
$c = q("select uid, aid, body, item_private from item where uuid = '%s'",
|
||||
dbesc($argv[1])
|
||||
);
|
||||
|
||||
if(! $c)
|
||||
if(!$c) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item = $c[0];
|
||||
|
||||
// bbcode conversion by default processes embeds that aren't already cached.
|
||||
// Ignore the returned html output.
|
||||
|
||||
bbcode($item['body']);
|
||||
|
||||
// photocache addon hook to prefetch one copy of public item images for the sys channel
|
||||
call_hooks('cache_prefetch_hook', $item);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class Channel_purge {
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rv) {
|
||||
drop_item($rv['id'], false);
|
||||
drop_item($rv['id'], uid: $channel_id);
|
||||
}
|
||||
}
|
||||
} while ($r);
|
||||
|
||||
@@ -38,7 +38,13 @@ class Content_importer {
|
||||
|
||||
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
|
||||
|
||||
$x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]);
|
||||
$redirects = 0;
|
||||
$x = z_fetch_url(
|
||||
$hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,
|
||||
false,
|
||||
$redirects,
|
||||
[ 'headers' => $headers ]
|
||||
);
|
||||
|
||||
// logger('item fetch: ' . print_r($x,true));
|
||||
|
||||
@@ -47,9 +53,9 @@ class Content_importer {
|
||||
killme();
|
||||
}
|
||||
|
||||
$j = json_decode($x['body'],true);
|
||||
$j = json_decode($x['body'], true);
|
||||
|
||||
if(! is_array($j['item']) || ! count($j['item'])) {
|
||||
if($j && empty($j['item'])) {
|
||||
PConfig::Set($channel['channel_id'], 'import', 'content_completed', 1);
|
||||
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;
|
||||
|
||||
@@ -69,18 +71,18 @@ class Cron {
|
||||
|
||||
// expire any expired items
|
||||
|
||||
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
|
||||
$r = q("select id, uid, item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
|
||||
and item_deleted = 0 ",
|
||||
db_utcnow()
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
require_once('include/items.php');
|
||||
foreach ($r as $rr) {
|
||||
drop_item($rr['id'], false, (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
|
||||
// pass uid of the message for permission check as we are running as a daemon process with no session.
|
||||
drop_item($rr['id'], (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL), uid: intval($rr['uid']));
|
||||
if ($rr['item_wall']) {
|
||||
// The notifier isn't normally invoked unless item_drop is interactive.
|
||||
Master::Summon(['Notifier', 'drop', $rr['id']]);
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
@@ -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)) {
|
||||
@@ -147,40 +150,29 @@ class Cron {
|
||||
// (time travel posts). Restrict to items that have come of age in the last
|
||||
// couple of days to limit the query to something reasonable.
|
||||
|
||||
$r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
|
||||
$r = q("select * from item where item_delayed = 1 and created <= %s and created > '%s' ",
|
||||
db_utcnow(),
|
||||
dbesc(datetime_convert('UTC', 'UTC', 'now - 2 days'))
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$x = q("update item set item_delayed = 0 where id = %d",
|
||||
intval($rr['id'])
|
||||
);
|
||||
if ($x) {
|
||||
$z = q("select * from item where id = %d",
|
||||
intval($rr['id'])
|
||||
);
|
||||
if ($z) {
|
||||
xchan_query($z);
|
||||
$sync_item = fetch_post_tags($z);
|
||||
Libsync::build_sync_packet($sync_item[0]['uid'],
|
||||
[
|
||||
'item' => [encode_item($sync_item[0], true)]
|
||||
]
|
||||
);
|
||||
}
|
||||
Master::Summon(array('Notifier', 'wall-new', $rr['id']));
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
if ($r) {
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r);
|
||||
foreach ($items as $item) {
|
||||
$item['item_delayed'] = 0;
|
||||
$post = item_store_update($item);
|
||||
|
||||
if($post['success']) {
|
||||
Master::Summon(['Notifier', 'wall-new', $post['item_id']]);
|
||||
if (!empty($post['approval_id'])) {
|
||||
Master::Summon(['Notifier', 'wall-new', $post['approval_id']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
require_once('include/attach.php');
|
||||
attach_upgrade();
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
// once daily run birthday_updates and then expire in background
|
||||
|
||||
// FIXME: add birthday updates, both locally and for xprof for use
|
||||
@@ -246,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
|
||||
|
||||
@@ -23,13 +23,13 @@ class Expire {
|
||||
|
||||
// perform final cleanup on previously delete items
|
||||
|
||||
$r = q("select id from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
|
||||
$r = q("select id, uid from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval('10 DAY')
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
drop_item($rr['id'], false, DROPITEM_PHASE2);
|
||||
drop_item($rr['id'], DROPITEM_PHASE2, uid: $rr['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,13 @@ class File_importer {
|
||||
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),true,'sha512');
|
||||
|
||||
// TODO: implement total count
|
||||
$x = z_fetch_url($hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page, false, $redirects, [ 'headers' => $headers ]);
|
||||
$redirects = 0;
|
||||
$x = z_fetch_url(
|
||||
$hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page,
|
||||
false,
|
||||
$redirects,
|
||||
[ 'headers' => $headers ]
|
||||
);
|
||||
// logger('file fetch: ' . print_r($x,true));
|
||||
|
||||
if(! $x['success']) {
|
||||
|
||||
@@ -11,6 +11,21 @@ class Importdoc {
|
||||
|
||||
self::update_docs_dir('doc/*');
|
||||
|
||||
$sys = get_sys_channel();
|
||||
|
||||
// remove old files that weren't updated (indicates they were most likely deleted).
|
||||
$i = q("select id from item where uid = %d and item_type = 5 and edited < %s - INTERVAL %s",
|
||||
intval($sys['channel_id']),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('14 DAY')
|
||||
);
|
||||
|
||||
if ($i) {
|
||||
foreach ($i as $iv) {
|
||||
drop_item($iv['id'], uid: $sys['channel_id']);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@@ -18,9 +33,13 @@ class Importdoc {
|
||||
static public function update_docs_dir($s) {
|
||||
$f = basename($s);
|
||||
$d = dirname($s);
|
||||
if ($s === 'doc/html')
|
||||
|
||||
if ($s === 'doc/html') {
|
||||
return;
|
||||
}
|
||||
|
||||
$files = glob("$d/$f");
|
||||
|
||||
if ($files) {
|
||||
foreach ($files as $fi) {
|
||||
if ($fi === 'doc/html') {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -241,11 +243,6 @@ class Notifier {
|
||||
|
||||
$target_item = $r[0];
|
||||
|
||||
if (in_array($target_item['author']['xchan_network'], ['rss', 'anon', 'token'])) {
|
||||
logger('notifier: target item author is not a fetchable actor', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
if (intval($target_item['item_deleted'])) {
|
||||
logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
|
||||
}
|
||||
@@ -268,22 +265,8 @@ class Notifier {
|
||||
|
||||
}
|
||||
|
||||
// Check for non published items, but allow an exclusion for transmitting hidden file activities
|
||||
|
||||
if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
|
||||
intval($target_item['item_blocked']) || intval($target_item['item_hidden'])) {
|
||||
logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
// follow/unfollow is for internal use only
|
||||
if (in_array($target_item['verb'], ['Follow', 'Ignore', ACTIVITY_FOLLOW, ACTIVITY_UNFOLLOW])) {
|
||||
logger('not fowarding follow/unfollow note activity');
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($target_item['postopts'], 'nodeliver') !== false) {
|
||||
logger('notifier: target item is undeliverable', LOGGER_DEBUG);
|
||||
if (!item_forwardable($target_item)) {
|
||||
logger('notifier: target item not forwardable', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -299,7 +282,7 @@ class Notifier {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($target_item['verb'] === ACTIVITY_SHARE) {
|
||||
if (in_array($target_item['verb'], [ACTIVITY_SHARE])) {
|
||||
// Provide correct representation across the wire. Internally this is treated as a comment.
|
||||
$target_item['parent_mid'] = $target_item['thr_parent'] = $target_item['mid'];
|
||||
}
|
||||
@@ -335,13 +318,24 @@ 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 {
|
||||
self::$encoded_item = Activity::build_packet(Activity::encode_activity($target_item), self::$channel, false);
|
||||
$activity = Activity::encode_activity($target_item);
|
||||
|
||||
if (!$activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$encoded_item = Activity::build_packet($activity, self::$channel, false);
|
||||
}
|
||||
|
||||
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
|
||||
@@ -358,6 +352,10 @@ class Notifier {
|
||||
|
||||
$relay_to_owner = (!$top_level_post && intval($target_item['item_origin']) && comment_local_origin($target_item));
|
||||
|
||||
if (self::$channel['channel_hash'] === $target_item['owner_xchan']) {
|
||||
$relay_to_owner = false;
|
||||
}
|
||||
|
||||
// $cmd === 'relay' indicates the owner is sending it to the original recipients
|
||||
// don't allow the item in the relay command to relay to owner under any circumstances, it will loop
|
||||
|
||||
@@ -374,7 +372,6 @@ class Notifier {
|
||||
|
||||
if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
|
||||
logger('notifier: followup relay', LOGGER_DEBUG);
|
||||
// If the Parent item is an Announce the real owner is the parent author
|
||||
$sendto = (($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
|
||||
self::$recipients = [$sendto];
|
||||
self::$private = true;
|
||||
@@ -389,7 +386,7 @@ class Notifier {
|
||||
logger('normal (downstream) distribution', LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
if ($parent_item && $parent_item['item_private'] !== $target_item['item_private']) {
|
||||
if (($parent_item && $parent_item['item_private'] !== $target_item['item_private']) || (intval($target_item['item_restrict']) & 1)) {
|
||||
logger('conversation privacy mismatch - downstream delivery prevented');
|
||||
return;
|
||||
}
|
||||
@@ -589,8 +586,6 @@ class Notifier {
|
||||
|
||||
foreach ($dhubs as $hub) {
|
||||
|
||||
logger('notifier_hub: ' . $hub['hubloc_url'], LOGGER_DEBUG);
|
||||
|
||||
if ($hub['hubloc_network'] !== 'zot6') {
|
||||
$narr = [
|
||||
'channel' => self::$channel,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
352
Zotlabs/Entity/Account.php
Normal file
352
Zotlabs/Entity/Account.php
Normal file
@@ -0,0 +1,352 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Entity;
|
||||
|
||||
use Zotlabs\Lib\BaseObject;
|
||||
|
||||
class Account extends BaseObject
|
||||
{
|
||||
public $account_id;
|
||||
public $account_parent;
|
||||
public $account_default_channel;
|
||||
public $account_salt;
|
||||
public $account_password;
|
||||
public $account_email;
|
||||
public $account_external;
|
||||
public $account_language;
|
||||
public $account_created;
|
||||
public $account_lastlog;
|
||||
public $account_flags;
|
||||
public $account_roles;
|
||||
public $account_reset;
|
||||
public $account_expires;
|
||||
public $account_expire_notified;
|
||||
public $account_service_class;
|
||||
public $account_level;
|
||||
public $account_password_change;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->account_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_id
|
||||
* @return Account
|
||||
*/
|
||||
public function setId($account_id)
|
||||
{
|
||||
$this->account_id = $account_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->account_parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_parent
|
||||
* @return Account
|
||||
*/
|
||||
public function setParent($account_parent)
|
||||
{
|
||||
$this->account_parent = $account_parent;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefaultChannel()
|
||||
{
|
||||
return $this->account_default_channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_default_channel
|
||||
* @return Account
|
||||
*/
|
||||
public function setDefaultChannel($account_default_channel)
|
||||
{
|
||||
$this->account_default_channel = $account_default_channel;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSalt()
|
||||
{
|
||||
return $this->account_salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_salt
|
||||
* @return Account
|
||||
*/
|
||||
public function setSalt($account_salt)
|
||||
{
|
||||
$this->account_salt = $account_salt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->account_password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_password
|
||||
* @return Account
|
||||
*/
|
||||
public function setPassword($account_password)
|
||||
{
|
||||
$this->account_password = $account_password;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEmail()
|
||||
{
|
||||
return $this->account_email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_email
|
||||
* @return Account
|
||||
*/
|
||||
public function setEmail($account_email)
|
||||
{
|
||||
$this->account_email = $account_email;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getExternal()
|
||||
{
|
||||
return $this->account_external;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_external
|
||||
* @return Account
|
||||
*/
|
||||
public function setExternal($account_external)
|
||||
{
|
||||
$this->account_external = $account_external;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLanguage()
|
||||
{
|
||||
return $this->account_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_language
|
||||
* @return Account
|
||||
*/
|
||||
public function setLanguage($account_language)
|
||||
{
|
||||
$this->account_language = $account_language;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCreated()
|
||||
{
|
||||
return $this->account_created;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_created
|
||||
* @return Account
|
||||
*/
|
||||
public function setCreated($account_created)
|
||||
{
|
||||
$this->account_created = $account_created;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLastlog()
|
||||
{
|
||||
return $this->account_lastlog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_lastlog
|
||||
* @return Account
|
||||
*/
|
||||
public function setLastlog($account_lastlog)
|
||||
{
|
||||
$this->account_lastlog = $account_lastlog;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFlags()
|
||||
{
|
||||
return $this->account_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_flags
|
||||
* @return Account
|
||||
*/
|
||||
public function setFlags($account_flags)
|
||||
{
|
||||
$this->account_flags = $account_flags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRoles()
|
||||
{
|
||||
return $this->account_roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_roles
|
||||
* @return Account
|
||||
*/
|
||||
public function setRoles($account_roles)
|
||||
{
|
||||
$this->account_roles = $account_roles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getReset()
|
||||
{
|
||||
return $this->account_reset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_reset
|
||||
* @return Account
|
||||
*/
|
||||
public function setReset($account_reset)
|
||||
{
|
||||
$this->account_reset = $account_reset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getExpires()
|
||||
{
|
||||
return $this->account_expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_expires
|
||||
* @return Account
|
||||
*/
|
||||
public function setExpires($account_expires)
|
||||
{
|
||||
$this->account_expires = $account_expires;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getExpireNotified()
|
||||
{
|
||||
return $this->account_expire_notified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_expire_notified
|
||||
* @return Account
|
||||
*/
|
||||
public function setExpireNotified($account_expire_notified)
|
||||
{
|
||||
$this->account_expire_notified = $account_expire_notified;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getServiceClass()
|
||||
{
|
||||
return $this->account_service_class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_service_class
|
||||
* @return Account
|
||||
*/
|
||||
public function setServiceClass($account_service_class)
|
||||
{
|
||||
$this->account_service_class = $account_service_class;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLevel()
|
||||
{
|
||||
return $this->account_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_level
|
||||
* @return Account
|
||||
*/
|
||||
public function setLevel($account_level)
|
||||
{
|
||||
$this->account_level = $account_level;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPasswordChange()
|
||||
{
|
||||
return $this->account_password_change;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $account_password_change
|
||||
* @return Account
|
||||
*/
|
||||
public function setPasswordChange($account_password_change)
|
||||
{
|
||||
$this->account_password_change = $account_password_change;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
714
Zotlabs/Entity/Channel.php
Normal file
714
Zotlabs/Entity/Channel.php
Normal file
@@ -0,0 +1,714 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Entity;
|
||||
|
||||
use Zotlabs\Lib\BaseObject;
|
||||
|
||||
class Channel extends BaseObject
|
||||
{
|
||||
public $channel_id;
|
||||
public $channel_account_id;
|
||||
public $channel_primary;
|
||||
public $channel_name;
|
||||
public $channel_parent;
|
||||
public $channel_address;
|
||||
public $channel_guid;
|
||||
public $channel_guid_sig;
|
||||
public $channel_hash;
|
||||
public $channel_timezone;
|
||||
public $channel_location;
|
||||
public $channel_theme;
|
||||
public $channel_startpage;
|
||||
public $channel_pubkey;
|
||||
public $channel_prvkey;
|
||||
public $channel_epubkey;
|
||||
public $channel_eprvkey;
|
||||
public $channel_notifyflags;
|
||||
public $channel_pageflags;
|
||||
public $channel_dirdate;
|
||||
public $channel_lastpost;
|
||||
public $channel_deleted;
|
||||
public $channel_active;
|
||||
public $channel_max_anon_mail;
|
||||
public $channel_max_friend_req;
|
||||
public $channel_expire_days;
|
||||
public $channel_passwd_reset;
|
||||
public $channel_default_group;
|
||||
public $channel_allow_cid;
|
||||
public $channel_allow_gid;
|
||||
public $channel_deny_cid;
|
||||
public $channel_deny_gid;
|
||||
public $channel_removed;
|
||||
public $channel_system;
|
||||
public $channel_moved;
|
||||
public $channel_password;
|
||||
public $channel_salt;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->channel_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_id
|
||||
* @return Channel
|
||||
*/
|
||||
public function setId($channel_id)
|
||||
{
|
||||
$this->channel_id = $channel_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAccountId()
|
||||
{
|
||||
return $this->channel_account_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_account_id
|
||||
* @return Channel
|
||||
*/
|
||||
public function setAccountId($channel_account_id)
|
||||
{
|
||||
$this->channel_account_id = $channel_account_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPrimary()
|
||||
{
|
||||
return $this->channel_primary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_primary
|
||||
* @return Channel
|
||||
*/
|
||||
public function setPrimary($channel_primary)
|
||||
{
|
||||
$this->channel_primary = $channel_primary;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->channel_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_name
|
||||
* @return Channel
|
||||
*/
|
||||
public function setName($channel_name)
|
||||
{
|
||||
$this->channel_name = $channel_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->channel_parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_parent
|
||||
* @return Channel
|
||||
*/
|
||||
public function setParent($channel_parent)
|
||||
{
|
||||
$this->channel_parent = $channel_parent;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAddress()
|
||||
{
|
||||
return $this->channel_address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_address
|
||||
* @return Channel
|
||||
*/
|
||||
public function setAddress($channel_address)
|
||||
{
|
||||
$this->channel_address = $channel_address;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getGuid()
|
||||
{
|
||||
return $this->channel_guid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_guid
|
||||
* @return Channel
|
||||
*/
|
||||
public function setGuid($channel_guid)
|
||||
{
|
||||
$this->channel_guid = $channel_guid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getGuidSig()
|
||||
{
|
||||
return $this->channel_guid_sig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_guid_sig
|
||||
* @return Channel
|
||||
*/
|
||||
public function setGuidSig($channel_guid_sig)
|
||||
{
|
||||
$this->channel_guid_sig = $channel_guid_sig;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHash()
|
||||
{
|
||||
return $this->channel_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_hash
|
||||
* @return Channel
|
||||
*/
|
||||
public function setHash($channel_hash)
|
||||
{
|
||||
$this->channel_hash = $channel_hash;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTimezone()
|
||||
{
|
||||
return $this->channel_timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_timezone
|
||||
* @return Channel
|
||||
*/
|
||||
public function setTimezone($channel_timezone)
|
||||
{
|
||||
$this->channel_timezone = $channel_timezone;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLocation()
|
||||
{
|
||||
return $this->channel_location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_location
|
||||
* @return Channel
|
||||
*/
|
||||
public function setLocation($channel_location)
|
||||
{
|
||||
$this->channel_location = $channel_location;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTheme()
|
||||
{
|
||||
return $this->channel_theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_theme
|
||||
* @return Channel
|
||||
*/
|
||||
public function setTheme($channel_theme)
|
||||
{
|
||||
$this->channel_theme = $channel_theme;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getStartpage()
|
||||
{
|
||||
return $this->channel_startpage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_startpage
|
||||
* @return Channel
|
||||
*/
|
||||
public function setStartpage($channel_startpage)
|
||||
{
|
||||
$this->channel_startpage = $channel_startpage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPubkey()
|
||||
{
|
||||
return $this->channel_pubkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_pubkey
|
||||
* @return Channel
|
||||
*/
|
||||
public function setPubkey($channel_pubkey)
|
||||
{
|
||||
$this->channel_pubkey = $channel_pubkey;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPrvkey()
|
||||
{
|
||||
return $this->channel_prvkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_prvkey
|
||||
* @return Channel
|
||||
*/
|
||||
public function setPrvkey($channel_prvkey)
|
||||
{
|
||||
$this->channel_prvkey = $channel_prvkey;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEpubkey()
|
||||
{
|
||||
return $this->channel_epubkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_epubkey
|
||||
* @return Channel
|
||||
*/
|
||||
public function setEpubkey($channel_epubkey)
|
||||
{
|
||||
$this->channel_epubkey = $channel_epubkey;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEprvkey()
|
||||
{
|
||||
return $this->channel_eprvkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_eprvkey
|
||||
* @return Channel
|
||||
*/
|
||||
public function setEprvkey($channel_eprvkey)
|
||||
{
|
||||
$this->channel_eprvkey = $channel_eprvkey;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getNotifyflags()
|
||||
{
|
||||
return $this->channel_notifyflags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_notifyflags
|
||||
* @return Channel
|
||||
*/
|
||||
public function setNotifyflags($channel_notifyflags)
|
||||
{
|
||||
$this->channel_notifyflags = $channel_notifyflags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPageflags()
|
||||
{
|
||||
return $this->channel_pageflags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_pageflags
|
||||
* @return Channel
|
||||
*/
|
||||
public function setPageflags($channel_pageflags)
|
||||
{
|
||||
$this->channel_pageflags = $channel_pageflags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDirdate()
|
||||
{
|
||||
return $this->channel_dirdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_dirdate
|
||||
* @return Channel
|
||||
*/
|
||||
public function setDirdate($channel_dirdate)
|
||||
{
|
||||
$this->channel_dirdate = $channel_dirdate;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLastpost()
|
||||
{
|
||||
return $this->channel_lastpost;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_lastpost
|
||||
* @return Channel
|
||||
*/
|
||||
public function setLastpost($channel_lastpost)
|
||||
{
|
||||
$this->channel_lastpost = $channel_lastpost;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDeleted()
|
||||
{
|
||||
return $this->channel_deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_deleted
|
||||
* @return Channel
|
||||
*/
|
||||
public function setDeleted($channel_deleted)
|
||||
{
|
||||
$this->channel_deleted = $channel_deleted;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getActive()
|
||||
{
|
||||
return $this->channel_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_active
|
||||
* @return Channel
|
||||
*/
|
||||
public function setActive($channel_active)
|
||||
{
|
||||
$this->channel_active = $channel_active;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMaxAnonMail()
|
||||
{
|
||||
return $this->channel_max_anon_mail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_max_anon_mail
|
||||
* @return Channel
|
||||
*/
|
||||
public function setMaxAnonMail($channel_max_anon_mail)
|
||||
{
|
||||
$this->channel_max_anon_mail = $channel_max_anon_mail;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMaxFriendReq()
|
||||
{
|
||||
return $this->channel_max_friend_req;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_max_friend_req
|
||||
* @return Channel
|
||||
*/
|
||||
public function setMaxFriendReq($channel_max_friend_req)
|
||||
{
|
||||
$this->channel_max_friend_req = $channel_max_friend_req;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getExpireDays()
|
||||
{
|
||||
return $this->channel_expire_days;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_expire_days
|
||||
* @return Channel
|
||||
*/
|
||||
public function setExpireDays($channel_expire_days)
|
||||
{
|
||||
$this->channel_expire_days = $channel_expire_days;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPasswdReset()
|
||||
{
|
||||
return $this->channel_passwd_reset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_passwd_reset
|
||||
* @return Channel
|
||||
*/
|
||||
public function setPasswdReset($channel_passwd_reset)
|
||||
{
|
||||
$this->channel_passwd_reset = $channel_passwd_reset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefaultGroup()
|
||||
{
|
||||
return $this->channel_default_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_default_group
|
||||
* @return Channel
|
||||
*/
|
||||
public function setDefaultGroup($channel_default_group)
|
||||
{
|
||||
$this->channel_default_group = $channel_default_group;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAllowCid()
|
||||
{
|
||||
return $this->channel_allow_cid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_allow_cid
|
||||
* @return Channel
|
||||
*/
|
||||
public function setAllowCid($channel_allow_cid)
|
||||
{
|
||||
$this->channel_allow_cid = $channel_allow_cid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAllowGid()
|
||||
{
|
||||
return $this->channel_allow_gid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_allow_gid
|
||||
* @return Channel
|
||||
*/
|
||||
public function setAllowGid($channel_allow_gid)
|
||||
{
|
||||
$this->channel_allow_gid = $channel_allow_gid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDenyCid()
|
||||
{
|
||||
return $this->channel_deny_cid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_deny_cid
|
||||
* @return Channel
|
||||
*/
|
||||
public function setDenyCid($channel_deny_cid)
|
||||
{
|
||||
$this->channel_deny_cid = $channel_deny_cid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDenyGid()
|
||||
{
|
||||
return $this->channel_deny_gid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_deny_gid
|
||||
* @return Channel
|
||||
*/
|
||||
public function setDenyGid($channel_deny_gid)
|
||||
{
|
||||
$this->channel_deny_gid = $channel_deny_gid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRemoved()
|
||||
{
|
||||
return $this->channel_removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_removed
|
||||
* @return Channel
|
||||
*/
|
||||
public function setRemoved($channel_removed)
|
||||
{
|
||||
$this->channel_removed = $channel_removed;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSystem()
|
||||
{
|
||||
return $this->channel_system;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_system
|
||||
* @return Channel
|
||||
*/
|
||||
public function setSystem($channel_system)
|
||||
{
|
||||
$this->channel_system = $channel_system;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMoved()
|
||||
{
|
||||
return $this->channel_moved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_moved
|
||||
* @return Channel
|
||||
*/
|
||||
public function setMoved($channel_moved)
|
||||
{
|
||||
$this->channel_moved = $channel_moved;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->channel_password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_password
|
||||
* @return Channel
|
||||
*/
|
||||
public function setPassword($channel_password)
|
||||
{
|
||||
$this->channel_password = $channel_password;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSalt()
|
||||
{
|
||||
return $this->channel_salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $channel_salt
|
||||
* @return Channel
|
||||
*/
|
||||
public function setSalt($channel_salt)
|
||||
{
|
||||
$this->channel_salt = $channel_salt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
1498
Zotlabs/Entity/Item.php
Normal file
1498
Zotlabs/Entity/Item.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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,31 +151,22 @@ 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)) {
|
||||
$fn = serialize($fn);
|
||||
}
|
||||
|
||||
if(! is_array(App::$hooks))
|
||||
App::$hooks = array();
|
||||
|
||||
@@ -119,4 +176,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;
|
||||
|
||||
|
||||
80
Zotlabs/Lib/BaseObject.php
Normal file
80
Zotlabs/Lib/BaseObject.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\ActivityStreams\UnhandledElementException;
|
||||
|
||||
class BaseObject
|
||||
{
|
||||
|
||||
public $string;
|
||||
public $ldContext;
|
||||
|
||||
/**
|
||||
* @param $input
|
||||
* @param $strict
|
||||
* @throws UnhandledElementException if $strict
|
||||
*/
|
||||
|
||||
public function __construct($input = null, $strict = false)
|
||||
{
|
||||
if (isset($input)) {
|
||||
if (is_string($input)) {
|
||||
$this->string = $input;
|
||||
}
|
||||
elseif(is_array($input)) {
|
||||
foreach ($input as $key => $value) {
|
||||
$key = ($key === '@context') ? 'ldContext' : $key;
|
||||
if ($strict && !property_exists($this, $key)) {
|
||||
throw new UnhandledElementException("Unhandled element: $key");
|
||||
}
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDataType($element, $object = null)
|
||||
{
|
||||
$object = $object ?? $this;
|
||||
$type = gettype($object[$element]);
|
||||
if ($type === 'array' && array_is_list($object[$element])) {
|
||||
return 'list';
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
if ($this->string) {
|
||||
return $this->string;
|
||||
}
|
||||
$returnValue = [];
|
||||
foreach ((array) $this as $key => $value) {
|
||||
if (isset($value)) {
|
||||
$key = ($key === 'ldContext') ? '@context' : $key;
|
||||
$returnValue[$key] = (($value instanceof BaseObject) ? $value->toArray() : $value);
|
||||
}
|
||||
}
|
||||
return $returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLdContext()
|
||||
{
|
||||
return $this->ldContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $ldContext
|
||||
* @return BaseObject
|
||||
*/
|
||||
public function setLdContext($ldContext)
|
||||
{
|
||||
$this->ldContext = $ldContext;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,7 @@ class Chatroom {
|
||||
}
|
||||
|
||||
|
||||
function leave($observer_xchan, $room_id, $client) {
|
||||
public static function leave($observer_xchan, $room_id, $client) {
|
||||
if(! $room_id || ! $observer_xchan)
|
||||
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
|
||||
|
||||
@@ -24,10 +24,16 @@ class Connect {
|
||||
|
||||
$uid = $channel['channel_id'];
|
||||
|
||||
if (strpos($url,'@') === false && strpos($url,'/') === false) {
|
||||
// If we get just a channel name and it is not an URL turn it into a local webbie
|
||||
if (!str_contains($url, '@') && strpos($url,'/') === false) {
|
||||
$url = $url . '@' . App::get_hostname();
|
||||
}
|
||||
|
||||
// Remove a possible leading @
|
||||
if (str_starts_with($url, '@')) {
|
||||
$url = ltrim($url, '@');
|
||||
}
|
||||
|
||||
$result = [ 'success' => false, 'message' => '' ];
|
||||
|
||||
$my_perms = false;
|
||||
|
||||
@@ -1,18 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* A class to handle database schema upgrades.
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
/**
|
||||
* Upgrade the database schema if necessary.
|
||||
*
|
||||
* Compares the currently active database schema version with the version
|
||||
* required for this version of Hubzilla, and performs the upgrade if needed.
|
||||
*
|
||||
* If the difference consists of more than one revision of the schema, each of
|
||||
* the intermediate upgrades are performed in turn.
|
||||
*/
|
||||
class DB_Upgrade {
|
||||
|
||||
public $config_name = '';
|
||||
public $func_prefix = '';
|
||||
|
||||
function __construct($db_revision) {
|
||||
|
||||
$this->config_name = 'db_version';
|
||||
$this->func_prefix = '_';
|
||||
/**
|
||||
* Check the installed and required schema versions and perform the upgrade
|
||||
* if necessary.
|
||||
*
|
||||
* @param int $db_version The required DB schema version.
|
||||
*/
|
||||
public static function run(int $db_revision): void {
|
||||
|
||||
$build = Config::Get('system', 'db_version', 0);
|
||||
if(! intval($build))
|
||||
|
||||
@@ -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'));
|
||||
|
||||
}
|
||||
|
||||
@@ -213,28 +213,36 @@ class Enotify {
|
||||
//$possess_desc = str_replace('<!item_type!>',$possess_desc);
|
||||
|
||||
// "a post"
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]a %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
|
||||
// "George Bull's post"
|
||||
if($p)
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
|
||||
if($p) {
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]%4$s\'s %5$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$p[0]['author']['xchan_name'],
|
||||
$item_post_type);
|
||||
$parent_item['author']['xchan_name'],
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
if ($parent_item['owner']['xchan_hash'] === $recip['channel_hash'] && intval($parent_item['item_wall'])) {
|
||||
$dest_str = sprintf(
|
||||
t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$action,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
|
||||
// Some mail softwares relies on subject field for threading.
|
||||
// So, we cannot have different subjects for notifications of the same thread.
|
||||
@@ -263,7 +271,7 @@ class Enotify {
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]))) {
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE, 'Announce']))) {
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
pop_lang();
|
||||
@@ -308,7 +316,6 @@ class Enotify {
|
||||
$item_post_type = item_post_type($p[0]);
|
||||
// $private = $p[0]['item_private'];
|
||||
$parent_id = $p[0]['id'];
|
||||
|
||||
$parent_item = $p[0];
|
||||
|
||||
//$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked'));
|
||||
@@ -320,14 +327,18 @@ class Enotify {
|
||||
if(activity_match($params['item']['verb'], ['Dislike', ACTIVITY_DISLIKE]))
|
||||
$verb = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
if(activity_match($params['item']['verb'], [ACTIVITY_SHARE]))
|
||||
$verb = (($moderated) ? t('requested to repeat') : t('repeated'));
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] === $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
if ($parent_item['author']['xchan_hash'] === $recip['channel_hash']) {
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$verb,
|
||||
$itemlink,
|
||||
$item_post_type
|
||||
);
|
||||
}
|
||||
else {
|
||||
pop_lang();
|
||||
return;
|
||||
@@ -406,6 +417,7 @@ class Enotify {
|
||||
}
|
||||
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_TAGSHARE) {
|
||||
$itemlink = $params['link'];
|
||||
$subject = sprintf( t('[$Projectname:Notify] %s tagged your post') , $sender['xchan_name']);
|
||||
$preamble = sprintf( t('%1$s tagged your post at %2$s'),$sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s tagged [zrl=%2$s]your post[/zrl]') ,
|
||||
@@ -415,12 +427,11 @@ class Enotify {
|
||||
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl );
|
||||
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
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]');
|
||||
@@ -433,6 +444,7 @@ class Enotify {
|
||||
}
|
||||
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_SUGGEST) {
|
||||
$itemlink = $params['link'];
|
||||
$subject = sprintf( t('[$Projectname:Notify] Friend suggestion received'));
|
||||
$preamble = sprintf( t('You\'ve received a friend suggestion from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('You\'ve received [zrl=%1$s]a friend suggestion[/zrl] for %2$s from %3$s.'),
|
||||
@@ -447,7 +459,6 @@ class Enotify {
|
||||
$sitelink = t('Please visit %s to approve or reject the suggestion.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl );
|
||||
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_CONFIRM) {
|
||||
@@ -500,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'];
|
||||
@@ -561,8 +577,9 @@ class Enotify {
|
||||
dbesc($datarray['otype'])
|
||||
);
|
||||
|
||||
$r = q("select id from notify where hash = '%s' and ntype = %d and uid = %d limit 1",
|
||||
$r = q("select id from notify where hash = '%s' and link = '%s' and ntype = %d and uid = %d limit 1",
|
||||
dbesc($datarray['hash']),
|
||||
dbesc($itemlink),
|
||||
intval($datarray['ntype']),
|
||||
intval($recip['channel_id'])
|
||||
);
|
||||
@@ -595,7 +612,7 @@ class Enotify {
|
||||
|
||||
// send email notification if notification preferences permit
|
||||
|
||||
require_once('bbcode.php');
|
||||
require_once('include/bbcode.php');
|
||||
if ((intval($recip['channel_notifyflags']) & intval($params['type'])) || $params['type'] == NOTIFY_SYSTEM) {
|
||||
|
||||
logger('notification: sending notification email');
|
||||
@@ -840,8 +857,8 @@ class Enotify {
|
||||
}
|
||||
else {
|
||||
$itemem_text = (($item['item_thread_top'])
|
||||
? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
? (($item['obj_type'] === 'Question') ? t('started a poll') : t('started a conversation'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('posted in %s\'s conversation'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
);
|
||||
|
||||
if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
|
||||
@@ -853,12 +870,7 @@ class Enotify {
|
||||
|
||||
if($item['edited'] > $item['created']) {
|
||||
$edit = true;
|
||||
if($item['item_thread_top']) {
|
||||
$itemem_text = sprintf( t('edited a post dated %s'), relative_date($item['created']));
|
||||
}
|
||||
else {
|
||||
$itemem_text = sprintf( t('edited a comment dated %s'), relative_date($item['created']));
|
||||
}
|
||||
$itemem_text = sprintf( t('edited a message dated %s'), relative_date($item['created']));
|
||||
}
|
||||
|
||||
|
||||
@@ -878,7 +890,7 @@ class Enotify {
|
||||
'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
|
||||
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
|
||||
// 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''),
|
||||
'b64mid' => (($item['uuid']) ? $item['uuid'] : ''),
|
||||
'b64mid' => ((in_array($item['verb'] , ['Like', 'Dislike', 'Announce']) && !empty($item['thr_parent_uuid'])) ? $item['thr_parent_uuid'] : $item['uuid'] ?? ''),
|
||||
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])),
|
||||
'thread_top' => (($item['item_thread_top']) ? true : false),
|
||||
'message' => bbcode(escape_tags($itemem_text)),
|
||||
@@ -898,14 +910,13 @@ class Enotify {
|
||||
}
|
||||
|
||||
static public function format_notify($tt) {
|
||||
|
||||
$message = trim(strip_tags(bbcode($tt['msg'])));
|
||||
|
||||
if(strpos($message, $tt['xname']) === 0)
|
||||
$message = substr($message, strlen($tt['xname']) + 1);
|
||||
|
||||
$x = [
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['link'] : z_root() . '/notify/view/' . $tt['id']),
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_INTRO) ? z_root() . '/notify/view/' . $tt['id'] : $tt['link']),
|
||||
'name' => $tt['xname'],
|
||||
'url' => $tt['url'],
|
||||
'photo' => $tt['photo'],
|
||||
@@ -917,11 +928,9 @@ class Enotify {
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_intros($rr) {
|
||||
|
||||
return [
|
||||
'notify_link' => z_root() . '/connections#' . $rr['abook_id'],
|
||||
'name' => $rr['xchan_name'],
|
||||
|
||||
@@ -13,6 +13,7 @@ class IConfig {
|
||||
static public function Get(&$item, $family, $key, $default = false) {
|
||||
|
||||
$is_item = false;
|
||||
$iid = null;
|
||||
|
||||
if(is_array($item)) {
|
||||
$is_item = true;
|
||||
@@ -27,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;
|
||||
@@ -97,11 +123,11 @@ class IConfig {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if(intval($item))
|
||||
if(intval($item)) {
|
||||
$iid = intval($item);
|
||||
|
||||
if(! $iid)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(self::Get($item, $family, $key) === false) {
|
||||
$r = q("insert into iconfig( iid, cat, k, v, sharing ) values ( %d, '%s', '%s', '%s', %d ) ",
|
||||
@@ -148,11 +174,11 @@ class IConfig {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(intval($item))
|
||||
if(intval($item)) {
|
||||
$iid = intval($item);
|
||||
|
||||
if(! $iid)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return q("delete from iconfig where iid = %d and cat = '%s' and k = '%s' ",
|
||||
intval($iid),
|
||||
|
||||
@@ -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 = [
|
||||
@@ -45,14 +62,16 @@ class JcsEddsa2022 {
|
||||
try {
|
||||
$result = sodium_crypto_sign_verify_detached($base58->decode($encodedSignature), $optionsHash . $dataHash,
|
||||
(new Multibase())->decode($publicKey, true));
|
||||
|
||||
logger('SignatureVerify (eddsa-jcs-2022) ' . (($result) ? 'true' : 'false'));
|
||||
|
||||
return $result;
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
logger('verify exception:' . $e->getMessage());
|
||||
}
|
||||
|
||||
logger('SignatureVerify (eddsa-jcs-2022) ' . (($result) ? 'true' : 'false'));
|
||||
|
||||
return $result;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function signableData($data) {
|
||||
@@ -85,8 +104,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;
|
||||
}
|
||||
|
||||
@@ -885,7 +876,7 @@ class Libsync {
|
||||
dbesc($t)
|
||||
);
|
||||
|
||||
q("update hubloc set hubloc_error = 1, hubloc_deleted = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s'",
|
||||
q("update hubloc set hubloc_error = 1, hubloc_deleted = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s' and hubloc_network = 'zot6'",
|
||||
dbesc($r[0]['hubloc_url']),
|
||||
dbesc($r[0]['hubloc_sitekey'])
|
||||
);
|
||||
|
||||
@@ -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', '');
|
||||
@@ -655,6 +651,11 @@ class Libzot {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if (empty($arr['primary_location']['address'])) {
|
||||
logger('Empty primary location address: ' . print_r($arr, true), LOGGER_DEBUG);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hooks import_xchan
|
||||
* Called when processing the result of zot_finger() to store the result
|
||||
@@ -1134,6 +1135,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
$message_request = false;
|
||||
$is_collection_operation = false;
|
||||
|
||||
|
||||
$has_data = array_key_exists('data', $env) && $env['data'];
|
||||
@@ -1141,15 +1143,33 @@ class Libzot {
|
||||
|
||||
$AS = null;
|
||||
|
||||
|
||||
if ($env['encoding'] === 'activitystreams') {
|
||||
|
||||
$AS = new ActivityStreams($data);
|
||||
if (!$AS->is_valid()) {
|
||||
logger('Activity rejected: ' . print_r($data, true));
|
||||
return;
|
||||
|
||||
// process add/remove from collection separately, as it requires a target.
|
||||
// use the data object, as it will not include actor expansion
|
||||
if (in_array($AS->type, ['Add', 'Remove'])
|
||||
&& is_array($AS->obj)
|
||||
&& array_key_exists('object', $AS->obj)
|
||||
&& array_key_exists('actor', $AS->obj)
|
||||
&& !empty($AS->tgt)) {
|
||||
|
||||
logger('relayed collection operation', LOGGER_DEBUG);
|
||||
$is_collection_operation = true;
|
||||
|
||||
$original_id = $AS->id;
|
||||
$original_type = $AS->type;
|
||||
|
||||
$raw_activity = $AS->data;
|
||||
|
||||
$AS = new ActivityStreams($raw_activity['object'], portable_id: $env['sender']);
|
||||
}
|
||||
|
||||
if (is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
|
||||
if (!$item) {
|
||||
logger('Could not decode activity: ' . print_r($AS, true));
|
||||
return;
|
||||
@@ -1158,6 +1178,12 @@ class Libzot {
|
||||
else {
|
||||
$item = [];
|
||||
}
|
||||
|
||||
if (!$AS->is_valid()) {
|
||||
logger('Activity rejected: ' . print_r($data, true));
|
||||
return;
|
||||
}
|
||||
|
||||
logger($AS->debug(), LOGGER_DATA);
|
||||
|
||||
}
|
||||
@@ -1198,7 +1224,6 @@ class Libzot {
|
||||
|
||||
logger('public post');
|
||||
|
||||
|
||||
// Public post. look for any site members who are or may be accepting posts from this sender
|
||||
// and who are allowed to see them based on the sender's permissions
|
||||
// @fixme;
|
||||
@@ -1265,25 +1290,6 @@ class Libzot {
|
||||
$item['item_private'] = 1;
|
||||
}
|
||||
|
||||
if ($item['mid'] === $item['parent_mid']) {
|
||||
if (is_array($AS->obj) && array_key_exists('commentPolicy', $AS->obj)) {
|
||||
$p = strstr($AS->obj['commentPolicy'], 'until=');
|
||||
if ($p !== false) {
|
||||
$comments_closed_at = datetime_convert('UTC', 'UTC', substr($p, 6));
|
||||
if ($comments_closed_at === $item['created']) {
|
||||
$item['item_nocomment'] = 1;
|
||||
}
|
||||
else {
|
||||
$item['comments_closed'] = $comments_closed_at;
|
||||
$aritemr['comment_policy'] = trim(str_replace($p, '', $AS->obj['commentPolicy']));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$item['comment_policy'] = $AS->obj['commentPolicy'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($AS->meta['hubloc']) || $AS->sigok) {
|
||||
$item['item_verified'] = true;
|
||||
}
|
||||
@@ -1292,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);
|
||||
@@ -1301,7 +1316,7 @@ class Libzot {
|
||||
|
||||
$relay = (($env['type'] === 'response') ? true : false);
|
||||
|
||||
$result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request);
|
||||
$result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request, false, $is_collection_operation);
|
||||
|
||||
Activity::init_background_fetch($env['sender']);
|
||||
}
|
||||
@@ -1517,7 +1532,7 @@ class Libzot {
|
||||
* @return array
|
||||
*/
|
||||
|
||||
static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false, $force = false) {
|
||||
static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false, $force = false, $is_collection_operation = false) {
|
||||
$result = [];
|
||||
|
||||
// We've validated the sender. Now make sure that the sender is the owner or author
|
||||
@@ -1532,6 +1547,7 @@ class Libzot {
|
||||
|
||||
$local_public = $public;
|
||||
$item_result = null;
|
||||
$parent = null;
|
||||
|
||||
$DR = new DReport(z_root(), $sender, $d, $arr['mid'], $arr['uuid']);
|
||||
|
||||
@@ -1545,6 +1561,14 @@ class Libzot {
|
||||
|
||||
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
|
||||
|
||||
$conversation_operation = $is_collection_operation && isset($arr['target']['attributedTo']);
|
||||
|
||||
if (isset($arr['tgt_type']) && str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
|
||||
$DR->update('not a collection activity');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (($act) && ($act->obj) && (!is_array($act->obj))) {
|
||||
// The initial object fetch failed using the sys channel credentials.
|
||||
// Try again using the delivery channel credentials.
|
||||
@@ -1578,6 +1602,8 @@ class Libzot {
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
if ($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && !str_starts_with($arr['mid'], z_root())) {
|
||||
$DR->update('self delivery ignored');
|
||||
$result[] = $DR->get();
|
||||
@@ -1624,22 +1650,32 @@ class Libzot {
|
||||
if (intval($channel['channel_system']) && (!$arr['item_private']) && (!$relay)) {
|
||||
$local_public = true;
|
||||
|
||||
$r = q("select xchan_selfcensored from xchan where xchan_hash = '%s' limit 1",
|
||||
$incl = Config::Get('system','pubstream_incl', '');
|
||||
$excl = Config::Get('system','pubstream_excl', '');
|
||||
|
||||
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'",
|
||||
dbesc($sender)
|
||||
);
|
||||
// don't import sys channel posts from selfcensored authors
|
||||
if ($r && (intval($r[0]['xchan_selfcensored']))) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
$incl = Config::Get('system','pubstream_incl');
|
||||
$excl = Config::Get('system','pubstream_excl');
|
||||
|
||||
if(($incl || $excl) && !MessageFilter::evaluate($arr, $incl, $excl)) {
|
||||
$local_public = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$tag_delivery = tgroup_check($channel['channel_id'], $arr);
|
||||
@@ -1701,6 +1737,7 @@ class Libzot {
|
||||
// If this is a poll response, convert the obj_type to our (internal-only) "Answer" type
|
||||
if (in_array($arr['obj_type'], ['Note', ACTIVITY_OBJ_COMMENT]) && $arr['title'] && (!$arr['body'])) {
|
||||
$arr['obj_type'] = 'Answer';
|
||||
$arr['item_hidden'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1805,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) {
|
||||
@@ -1826,11 +1861,12 @@ class Libzot {
|
||||
dbesc($arr['author_xchan'])
|
||||
);
|
||||
|
||||
// reactions such as like and dislike could have an mid with /activity/ in it.
|
||||
// Reactions such as like and dislike could have an mid with /activity/ in it.
|
||||
// Check for both forms in order to prevent duplicates.
|
||||
$r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1",
|
||||
|
||||
$r = q("select * from item where mid in ('%s', '%s') and uid = %d limit 1",
|
||||
dbesc($arr['mid']),
|
||||
dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])),
|
||||
dbesc(reverse_activity_mid($arr['mid'])),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
@@ -1859,21 +1895,31 @@ class Libzot {
|
||||
$DR->update('update ignored');
|
||||
$result[] = $DR->get();
|
||||
}
|
||||
|
||||
if ($relay && $channel['channel_hash'] === $item_result['item']['owner_xchan'] && $item_result['item']['verb'] !== 'Add' && !$is_collection_operation) {
|
||||
$approval = Activity::addToCollection($channel, $act->data, $item_result['item']['parent_mid'], $item_result['item'], deliver: false);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
$DR->update('update ignored');
|
||||
$result[] = $DR->get();
|
||||
|
||||
// We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit),
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
$arr['aid'] = $channel['channel_account_id'];
|
||||
$arr['uid'] = $channel['channel_id'];
|
||||
|
||||
|
||||
// if it's a sourced post, call the post_local hooks as if it were
|
||||
// posted locally so that crosspost connectors will be triggered.
|
||||
$item_source = check_item_source($arr['uid'], $arr);
|
||||
@@ -1902,10 +1948,15 @@ class Libzot {
|
||||
}
|
||||
|
||||
if (post_is_importable($arr['uid'], $arr, $abook)) {
|
||||
$item_result = item_store($arr);
|
||||
$item_result = item_store($arr, addAndSync: false);
|
||||
|
||||
if ($item_result['success']) {
|
||||
$item_id = $item_result['item_id'];
|
||||
|
||||
if ($relay && $channel['channel_hash'] === $item_result['item']['owner_xchan'] && $item_result['item']['verb'] !== 'Add' && !$is_collection_operation) {
|
||||
$approval = Activity::addToCollection($channel, $act->data, $item_result['item']['parent_mid'], $item_result['item'], deliver: false);
|
||||
}
|
||||
|
||||
if ($item_source && in_array($item_result['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
|
||||
event_addtocal($item_id, $channel['channel_id']);
|
||||
}
|
||||
@@ -1948,14 +1999,18 @@ class Libzot {
|
||||
|
||||
if ((is_array($stored)) && ($stored['id'] != $stored['parent'])
|
||||
&& ($stored['author_xchan'] === $channel['channel_hash'])) {
|
||||
retain_item($stored['item']['parent']);
|
||||
retain_item($stored['parent']);
|
||||
}
|
||||
|
||||
if ($relay && $item_id && $stored['item_blocked'] !== ITEM_MODERATED) {
|
||||
if ($relay && $item_id && item_forwardable($stored)) {
|
||||
logger('Invoking relay');
|
||||
Master::Summon(['Notifier', 'relay', intval($item_id)]);
|
||||
if (!empty($approval) && $approval['item_id']) {
|
||||
Master::Summon(['Notifier', 'relay', intval($approval['item_id'])]);
|
||||
}
|
||||
|
||||
$DR->addto_update('relayed');
|
||||
$result[] = $DR->get();
|
||||
$result = [$DR->get()];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2006,6 +2061,7 @@ class Libzot {
|
||||
foreach ($items as $activity) {
|
||||
|
||||
$AS = new ActivityStreams($activity);
|
||||
|
||||
if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj)
|
||||
&& array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj)) {
|
||||
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
|
||||
@@ -2014,6 +2070,30 @@ class Libzot {
|
||||
$AS = new ActivityStreams($AS->obj);
|
||||
}
|
||||
|
||||
// process add/remove from collection separately, as it requires a target.
|
||||
// use the raw object, as it will not include actor expansion
|
||||
if (in_array($AS->type, ['Add', 'Remove'])
|
||||
&& is_array($AS->obj)
|
||||
&& array_key_exists('object', $AS->obj)
|
||||
&& array_key_exists('actor', $AS->obj)
|
||||
&& !empty($AS->tgt)) {
|
||||
|
||||
logger('relayed collection operation', LOGGER_DEBUG);
|
||||
|
||||
$is_collection_operation = true;
|
||||
|
||||
$original_id = $AS->id;
|
||||
$original_type = $AS->type;
|
||||
|
||||
$raw_activity = $AS->data;
|
||||
|
||||
$AS = new ActivityStreams($raw_activity['object']);
|
||||
|
||||
// Store the original activity id and type for later usage
|
||||
$AS->meta['original_id'] = $original_id;
|
||||
$AS->meta['original_type'] = $original_type;
|
||||
}
|
||||
|
||||
if (!$AS->is_valid()) {
|
||||
logger('Fetched activity rejected: ' . print_r($activity, true));
|
||||
continue;
|
||||
@@ -2081,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'])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2207,7 +2286,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
|
||||
$x = item_store_update($item);
|
||||
$x = item_store_update($item, addAndSync: false);
|
||||
|
||||
// If we're updating an event that we've saved locally, we store the item info first
|
||||
// because event_addtocal will parse the body to get the 'new' event details
|
||||
@@ -2323,21 +2402,20 @@ class Libzot {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if ($stored['id'] !== $stored['parent']) {
|
||||
q(
|
||||
"update item set commented = '%s', changed = '%s' where id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
intval($stored['parent'])
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($stored['id'] !== $stored['parent']) {
|
||||
q("update item set commented = '%s', changed = '%s' where id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
intval($stored['parent'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels
|
||||
// and then clean up after ourselves with a cron job after several days to do the delete_item_lowlevel() (DROPITEM_PHASE2).
|
||||
|
||||
drop_item($post_id, false, DROPITEM_PHASE1);
|
||||
drop_item($post_id, DROPITEM_PHASE1, uid: $uid);
|
||||
tag_deliver($uid, $post_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -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'])
|
||||
|
||||
86
Zotlabs/Lib/Mailer.php
Normal file
86
Zotlabs/Lib/Mailer.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* Mailer class for sending emails from Hubzilla.
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
|
||||
/**
|
||||
* A class for sending emails.
|
||||
*
|
||||
* Based on the previous `z_mail` function, but adaped and made more
|
||||
* robust and usable as a class.
|
||||
*/
|
||||
class Mailer {
|
||||
|
||||
public function __construct(private array $params = []) {
|
||||
}
|
||||
|
||||
public function deliver(): bool {
|
||||
|
||||
if(empty($this->params['fromEmail'])) {
|
||||
$this->params['fromEmail'] = Config::Get('system','from_email');
|
||||
if(empty($this->params['fromEmail'])) {
|
||||
$this->params['fromEmail'] = 'Administrator@' . App::get_hostname();
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($this->params['fromName'])) {
|
||||
$this->params['fromName'] = Config::Get('system','from_email_name');
|
||||
if(empty($this->params['fromName'])) {
|
||||
$this->params['fromName'] = System::get_site_name();
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($this->params['replyTo'])) {
|
||||
$this->params['replyTo'] = Config::Get('system','reply_address');
|
||||
if(empty($this->params['replyTo'])) {
|
||||
$this->params['replyTo'] = 'noreply@' . App::get_hostname();
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($this->params['additionalMailHeader'])) {
|
||||
$this->params['additionalMailHeader'] = '';
|
||||
}
|
||||
|
||||
$this->params['sent'] = false;
|
||||
$this->params['result'] = false;
|
||||
|
||||
/**
|
||||
* @hooks email_send
|
||||
* * \e params @see z_mail()
|
||||
*/
|
||||
call_hooks('email_send', $this->params);
|
||||
|
||||
if($this->params['sent']) {
|
||||
logger('notification: z_mail returns ' . (($this->params['result']) ? 'success' : 'failure'), LOGGER_DEBUG);
|
||||
return $this->params['result'];
|
||||
}
|
||||
|
||||
$fromName = email_header_encode(html_entity_decode($this->params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
|
||||
$messageSubject = email_header_encode(html_entity_decode($this->params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8');
|
||||
|
||||
$messageHeader =
|
||||
$this->params['additionalMailHeader'] .
|
||||
"From: $fromName <{$this->params['fromEmail']}>" . PHP_EOL .
|
||||
"Reply-To: $fromName <{$this->params['replyTo']}>" . PHP_EOL .
|
||||
"Content-Type: text/plain; charset=UTF-8";
|
||||
|
||||
// send the message
|
||||
$res = mail(
|
||||
$this->params['toEmail'], // send to address
|
||||
$messageSubject, // subject
|
||||
$this->params['textVersion'],
|
||||
$messageHeader // message headers
|
||||
);
|
||||
logger('notification: z_mail returns ' . (($res) ? 'success' : 'failure'), LOGGER_DEBUG);
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
/**
|
||||
* @brief wrapper for z_fetch_url() which can be instantiated with several built-in parameters and
|
||||
* these can be modified and re-used. Useful for CalDAV and other processes which need to authenticate
|
||||
* and set lots of CURL options (many of which stay the same from one call to the next).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
class SuperCurl {
|
||||
|
||||
|
||||
private $auth;
|
||||
private $url;
|
||||
|
||||
private $curlopt = array();
|
||||
|
||||
private $headers = null;
|
||||
public $filepos = 0;
|
||||
public $filehandle = 0;
|
||||
public $request_data = '';
|
||||
|
||||
private $request_method = 'GET';
|
||||
private $upload = false;
|
||||
private $cookies = false;
|
||||
|
||||
|
||||
private function set_data($s) {
|
||||
$this->request_data = $s;
|
||||
$this->filepos = 0;
|
||||
}
|
||||
|
||||
public function curl_read($ch,$fh,$size) {
|
||||
|
||||
if($this->filepos < 0) {
|
||||
unset($fh);
|
||||
return '';
|
||||
}
|
||||
|
||||
$s = substr($this->request_data,$this->filepos,$size);
|
||||
|
||||
if(strlen($s) < $size)
|
||||
$this->filepos = (-1);
|
||||
else
|
||||
$this->filepos = $this->filepos + $size;
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
public function __construct($opts = array()) {
|
||||
$this->set($opts);
|
||||
}
|
||||
|
||||
private function set($opts = array()) {
|
||||
if($opts) {
|
||||
foreach($opts as $k => $v) {
|
||||
switch($k) {
|
||||
case 'http_auth':
|
||||
$this->auth = $v;
|
||||
break;
|
||||
case 'magicauth':
|
||||
// currently experimental
|
||||
$this->magicauth = $v;
|
||||
\Zotlabs\Daemon\Master::Summon([ 'CurlAuth', $v ]);
|
||||
break;
|
||||
case 'custom':
|
||||
$this->request_method = $v;
|
||||
break;
|
||||
case 'url':
|
||||
$this->url = $v;
|
||||
break;
|
||||
case 'data':
|
||||
$this->set_data($v);
|
||||
if($v) {
|
||||
$this->upload = true;
|
||||
}
|
||||
else {
|
||||
$this->upload = false;
|
||||
}
|
||||
break;
|
||||
case 'headers':
|
||||
$this->headers = $v;
|
||||
break;
|
||||
default:
|
||||
$this->curlopts[$k] = $v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function exec() {
|
||||
$opts = $this->curlopts;
|
||||
$url = $this->url;
|
||||
if($this->auth)
|
||||
$opts['http_auth'] = $this->auth;
|
||||
if($this->magicauth) {
|
||||
$opts['cookiejar'] = 'store/[data]/cookie_' . $this->magicauth;
|
||||
$opts['cookiefile'] = 'store/[data]/cookie_' . $this->magicauth;
|
||||
$opts['cookie'] = 'PHPSESSID=' . trim(file_get_contents('store/[data]/cookien_' . $this->magicauth));
|
||||
$c = channelx_by_n($this->magicauth);
|
||||
if($c)
|
||||
$url = zid($this->url,channel_reddress($c));
|
||||
}
|
||||
if($this->custom)
|
||||
$opts['custom'] = $this->custom;
|
||||
if($this->headers)
|
||||
$opts['headers'] = $this->headers;
|
||||
if($this->upload) {
|
||||
$opts['upload'] = true;
|
||||
$opts['infile'] = $this->filehandle;
|
||||
$opts['infilesize'] = strlen($this->request_data);
|
||||
$opts['readfunc'] = [ $this, 'curl_read' ] ;
|
||||
}
|
||||
|
||||
$recurse = 0;
|
||||
return z_fetch_url($this->url,true,$recurse,(($opts) ? $opts : null));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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']));
|
||||
@@ -187,7 +185,7 @@ class ThreadItem {
|
||||
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
|
||||
}
|
||||
|
||||
$filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) ? t("Save to Folder") : false);
|
||||
$filer = (((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) ? t("Save to Folder") : false);
|
||||
|
||||
$profile_avatar = $item['author']['xchan_photo_s'];
|
||||
$profile_link = chanlink_hash($item['author_xchan']);
|
||||
@@ -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,56 +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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
$like_count = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid']] : '');
|
||||
$like_list = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid'] . '-l'] : '');
|
||||
if (($like_list) && (count($like_list) > MAX_LIKERS)) {
|
||||
$like_list_part = array_slice($like_list, 0, MAX_LIKERS);
|
||||
array_push($like_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
|
||||
} else {
|
||||
$like_list_part = '';
|
||||
}
|
||||
$like_button_label = tt('Like','Likes',$like_count,'noun');
|
||||
|
||||
$repeat_count = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid']] : '');
|
||||
$repeat_list = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid'] . '-l'] : '');
|
||||
if (($repeat_list) && (count($repeat_list) > MAX_LIKERS)) {
|
||||
$repeat_list_part = array_slice($repeat_list, 0, MAX_LIKERS);
|
||||
array_push($repeat_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#repeatModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
|
||||
} else {
|
||||
$repeat_list_part = '';
|
||||
}
|
||||
$repeat_button_label = tt('Repeat','Repeats',$repeat_count,'noun');
|
||||
|
||||
$showdislike = '';
|
||||
if (feature_enabled($conv->get_profile_owner(),'dislike')) {
|
||||
$dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : '');
|
||||
$dislike_list = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid'] . '-l'] : '');
|
||||
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
|
||||
if (($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
|
||||
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
|
||||
array_push($dislike_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
|
||||
} else {
|
||||
$dislike_list_part = '';
|
||||
}
|
||||
|
||||
$showdislike = ((x($conv_responses['dislike'],$item['mid'])) ? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : '');
|
||||
}
|
||||
|
||||
$showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : '');
|
||||
*/
|
||||
$response_verbs[] = 'comment';
|
||||
$responses = get_responses($response_verbs, $item);
|
||||
|
||||
/*
|
||||
* We should avoid doing this all the time, but it depends on the conversation mode
|
||||
@@ -281,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"),
|
||||
@@ -293,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') : '');
|
||||
@@ -326,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 = [];
|
||||
@@ -378,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);
|
||||
|
||||
@@ -390,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
|
||||
@@ -411,11 +357,26 @@ 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,
|
||||
'item_type' => intval($item['item_type']),
|
||||
//'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
|
||||
'body' => $body['html'],
|
||||
'tags' => $body['tags'],
|
||||
'categories' => $body['categories'],
|
||||
@@ -424,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,
|
||||
@@ -450,16 +411,15 @@ class ThreadItem {
|
||||
'sparkle' => $sparkle,
|
||||
'title' => $item['title'],
|
||||
'title_tosource' => get_pconfig($conv->get_profile_owner(),'system','title_tosource'),
|
||||
//'ago' => relative_date($item['created']),
|
||||
'app' => $item['app'],
|
||||
'str_app' => sprintf( t('from %s'), $item['app']),
|
||||
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
|
||||
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
|
||||
'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
|
||||
'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
|
||||
'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'] > DBA::$dba->get_null_date()) ? sprintf(t('Expires %s'), relative_time($item['expires'])) : ''),
|
||||
'lock' => $lock,
|
||||
'locktype' => $locktype,
|
||||
'delayed' => $item['item_delayed'],
|
||||
'delayed' => (($item['item_delayed']) ? sprintf(t('Published %s'), relative_time($item['created'])) : ''),
|
||||
'privacy_warning' => $privacy_warning,
|
||||
'verified' => $verified,
|
||||
'unverified' => $unverified,
|
||||
@@ -472,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(),
|
||||
@@ -479,17 +440,16 @@ class ThreadItem {
|
||||
'event' => $body['event'],
|
||||
'has_tags' => $has_tags,
|
||||
'reactions' => $this->reactions,
|
||||
// Item toolbar buttons
|
||||
// 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, // ((feature_enabled($conv->get_profile_owner(),'edit_posts')) ? $edpost : ''),
|
||||
'edpost' => $edpost,
|
||||
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts') && ($item['item_type'] == ITEM_TYPE_POST)) ? $star : ''),
|
||||
'tagger' => ((feature_enabled($conv->get_profile_owner(),'commtag')) ? $tagger : ''),
|
||||
'filer' => ((feature_enabled($conv->get_profile_owner(),'filing') && ($item['item_type'] == ITEM_TYPE_POST)) ? $filer : ''),
|
||||
@@ -500,51 +460,50 @@ class ThreadItem {
|
||||
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
|
||||
'drop' => $drop,
|
||||
'dropdown_extras' => $dropdown_extras,
|
||||
// end toolbar buttons
|
||||
// end toolbar buttons
|
||||
'unseen_comments' => $unseen_comments,
|
||||
'comment_count' => $total_children,
|
||||
'comment_count_txt' => $comment_count_txt,
|
||||
'list_unseen_txt' => $list_unseen_txt,
|
||||
'markseen' => t('Mark all comments seen'),
|
||||
'responses' => $responses,
|
||||
'my_responses' => $my_responses,
|
||||
/*
|
||||
'like_count' => $like_count,
|
||||
'like_list' => $like_list,
|
||||
'like_list_part' => $like_list_part,
|
||||
'like_button_label' => $like_button_label,
|
||||
'like_modal_title' => t('Likes','noun'),
|
||||
|
||||
'repeat_count' => $repeat_count,
|
||||
'repeat_list' => $repeat_list,
|
||||
'repeat_list_part' => $repeat_list_part,
|
||||
'repeat_button_label' => $repeat_button_label,
|
||||
'repeat_modal_title' => t('Repeats','noun'),
|
||||
|
||||
|
||||
'dislike_modal_title' => t('Dislikes','noun'),
|
||||
'dislike_count' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_count : ''),
|
||||
'dislike_list' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list : ''),
|
||||
'dislike_list_part' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list_part : ''),
|
||||
'dislike_button_label' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_button_label : ''),
|
||||
*/
|
||||
// 'my_responses' => $my_responses,
|
||||
'modal_dismiss' => t('Close'),
|
||||
// 'showlike' => $showlike,
|
||||
// 'showdislike' => $showdislike,
|
||||
'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'),
|
||||
'moderate_delete' => t('Delete'),
|
||||
'rtl' => in_array($item['lang'], rtl_languages()),
|
||||
'reactions_allowed' => $reactions_allowed,
|
||||
'reaction_str' => [t('Add yours'), t('Remove yours')]
|
||||
'reaction_str' => [t('Add yours'), t('Remove yours')],
|
||||
'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);
|
||||
@@ -553,33 +512,19 @@ class ThreadItem {
|
||||
$result = $arr['output'];
|
||||
|
||||
$result['children'] = array();
|
||||
$nb_children = count($children);
|
||||
|
||||
$visible_comments = Config::Get('system','expanded_comments');
|
||||
if($visible_comments === false)
|
||||
$visible_comments = 3;
|
||||
$visible_comments = 3; // Config::Get('system', 'expanded_comments', 3);
|
||||
|
||||
// needed for scroll to comment from notification but needs more work
|
||||
// as we do not want to open all comments unless there is actually an #item_xx anchor
|
||||
// and the url fragment is not sent to the server.
|
||||
// if(in_array(\App::$module,['display','update_display']))
|
||||
// $visible_comments = 99999;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,7 +777,7 @@ class ThreadItem {
|
||||
*/
|
||||
private function get_comment_box() {
|
||||
|
||||
if(!$this->is_toplevel() && !Config::Get('system','thread_allow')) {
|
||||
if(!$this->is_toplevel()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -868,14 +813,15 @@ class ThreadItem {
|
||||
'$submit' => t('Submit'),
|
||||
'$edbold' => t('Bold'),
|
||||
'$editalic' => t('Italic'),
|
||||
'$edhighlighter' => t('Highlight selected text'),
|
||||
'$eduline' => t('Underline'),
|
||||
'$edquote' => t('Quote'),
|
||||
'$edcode' => t('Code'),
|
||||
'$edimg' => t('Image'),
|
||||
'$edimg' => t('Embed (existing) photo from your photo albums'),
|
||||
'$edatt' => t('Attach/Upload file'),
|
||||
'$edurl' => t('Insert Link'),
|
||||
'$edvideo' => t('Video'),
|
||||
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
|
||||
'$preview' => t('Preview'),
|
||||
'$can_upload' => (perm_is_allowed($conv->get_profile_owner(),get_observer_hash(),'write_storage') && $conv->is_uploadable()),
|
||||
'$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false),
|
||||
'$encrypt' => t('Encrypt text'),
|
||||
@@ -896,12 +842,13 @@ class ThreadItem {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are a wall to wall item and set the relevant properties
|
||||
* Check if we are a wall to wall or announce item and set the relevant properties
|
||||
*/
|
||||
protected function check_wall_to_wall() {
|
||||
$conv = $this->get_conversation();
|
||||
$this->wall_to_wall = false;
|
||||
$this->owner_url = '';
|
||||
$this->owner_addr = '';
|
||||
$this->owner_photo = '';
|
||||
$this->owner_name = '';
|
||||
|
||||
@@ -910,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;
|
||||
@@ -930,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.")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
132
Zotlabs/Lib/Url.php
Normal file
132
Zotlabs/Lib/Url.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 The Hubzilla Community
|
||||
* SPDX-FileContributor: Mario Vavti <mario@mariovavti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
class Url {
|
||||
|
||||
/**
|
||||
* @brief Adds a zid parameter to a url.
|
||||
*
|
||||
* @param string $s
|
||||
* The url to accept the zid
|
||||
* @param string $address
|
||||
* $address to use instead of session environment
|
||||
* @return string
|
||||
*/
|
||||
public static function zid(string $url, string $address = ''): string
|
||||
{
|
||||
if (!$url || strpos($url, 'zid=') !== false) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$parts = parse_url($url);
|
||||
if ($parts === false) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$mine = get_my_url();
|
||||
$myaddr = $address ?: get_my_address();
|
||||
|
||||
if (!$mine || !$myaddr) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$mine_parts = parse_url($mine);
|
||||
$same_host = isset($mine_parts['host'], $parts['host']) && strcasecmp($mine_parts['host'], $parts['host']) === 0;
|
||||
|
||||
if ($same_host) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$query = [];
|
||||
if (!empty($parts['query'])) {
|
||||
parse_str($parts['query'], $query);
|
||||
}
|
||||
|
||||
$query['zid'] = $myaddr;
|
||||
$parts['query'] = http_build_query($query);
|
||||
|
||||
$hookdata = [
|
||||
'url' => $url,
|
||||
'zid' => urlencode($myaddr),
|
||||
'result' => self::unparse($parts)
|
||||
];
|
||||
|
||||
/**
|
||||
* @hooks zid
|
||||
* Called when adding the observer's zid to a URL.
|
||||
* * \e string \b url - url to accept zid
|
||||
* * \e string \b zid - urlencoded zid
|
||||
* * \e string \b result - the return string we calculated, change it if you want to return something else
|
||||
*/
|
||||
call_hooks('zid', $hookdata);
|
||||
|
||||
return $hookdata['result'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reconstructs a URL from its parsed components.
|
||||
*
|
||||
* This function takes a parsed URL as an associative array and reconstructs
|
||||
* the URL based on the specified components (scheme, host, port, user, pass, path, query, fragment).
|
||||
* You can specify which components should be included in the final URL by passing the optional
|
||||
* `$parts` array. The function will return the complete URL string formed by combining
|
||||
* only the parts that exist in both the parsed URL and the `$parts` array.
|
||||
*
|
||||
* @param array $parsed_url The parsed URL components as an associative array.
|
||||
* The array can include keys like 'scheme', 'host', 'port', 'user', 'pass',
|
||||
* 'path', 'query', 'fragment'.
|
||||
*
|
||||
* @param array $parts An optional array that specifies which components of the URL
|
||||
* should be included in the final string. Defaults to:
|
||||
* ['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'].
|
||||
* If any of the components are not required, they can be omitted from the array.
|
||||
*
|
||||
* @return string The reconstructed URL as a string.
|
||||
*/
|
||||
public static function unparse(array $parsed_url, array $parts = ['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment']): string {
|
||||
$url_parts = [];
|
||||
|
||||
if (in_array('scheme', $parts) && array_key_exists('scheme', $parsed_url)) {
|
||||
$url_parts[] = $parsed_url['scheme'] . '://';
|
||||
}
|
||||
|
||||
if (in_array('user', $parts) && array_key_exists('user', $parsed_url)) {
|
||||
$url_parts[] = $parsed_url['user'];
|
||||
if (in_array('pass', $parts) && array_key_exists('pass', $parsed_url)) {
|
||||
$url_parts[] = ':' . $parsed_url['pass'];
|
||||
}
|
||||
$url_parts[] = '@';
|
||||
}
|
||||
|
||||
if (in_array('host', $parts) && array_key_exists('host', $parsed_url)) {
|
||||
$url_parts[] = $parsed_url['host'];
|
||||
}
|
||||
|
||||
if (in_array('port', $parts) && array_key_exists('port', $parsed_url)) {
|
||||
$url_parts[] = ':' . $parsed_url['port'];
|
||||
}
|
||||
|
||||
if (in_array('path', $parts) && array_key_exists('path', $parsed_url)) {
|
||||
$url_parts[] = $parsed_url['path'];
|
||||
}
|
||||
|
||||
if (in_array('query', $parts) && array_key_exists('query', $parsed_url)) {
|
||||
$url_parts[] = '?' . $parsed_url['query'];
|
||||
}
|
||||
|
||||
if (in_array('fragment', $parts) && array_key_exists('fragment', $parsed_url)) {
|
||||
$url_parts[] = '#' . $parsed_url['fragment'];
|
||||
}
|
||||
|
||||
return implode('', $url_parts);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,25 +8,25 @@ class Achievements extends \Zotlabs\Web\Controller {
|
||||
// This doesn't work, so
|
||||
if (! is_developer())
|
||||
return;
|
||||
|
||||
|
||||
if(argc() > 1)
|
||||
$which = argv(1);
|
||||
else {
|
||||
notice( t('Requested profile is not available.') . EOL );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$profile = 0;
|
||||
$profile = argv(1);
|
||||
$profile = argv(1);
|
||||
profile_load($which,$profile);
|
||||
|
||||
|
||||
$r = q("select channel_id from channel where channel_address = '%s'",
|
||||
dbesc($which)
|
||||
);
|
||||
if($r) {
|
||||
$owner = intval($r[0]['channel_id']);
|
||||
}
|
||||
|
||||
|
||||
$observer = \App::get_observer();
|
||||
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
|
||||
$perms = get_all_perms($owner,$ob_hash);
|
||||
@@ -34,60 +34,60 @@ class Achievements extends \Zotlabs\Web\Controller {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$newmembertext = t('Some blurb about what to do when you\'re new here');
|
||||
|
||||
|
||||
|
||||
|
||||
// By default, all badges are false
|
||||
$contactbadge = false;
|
||||
$profilebadge = false;
|
||||
$keywordsbadge = false;
|
||||
|
||||
|
||||
// Check number of contacts. Award a badge if over 10
|
||||
// We'll figure these out on each page load instead of
|
||||
// We'll figure these out on each page load instead of
|
||||
// writing them to the DB because that will mean one needs
|
||||
// to retain their achievements - eg, you can't add
|
||||
// a bunch of channels just to get your badge, and then
|
||||
// delete them all again. If these become popular or
|
||||
// used in profiles or something, we may need to reconsider
|
||||
// and add a table for this - because this won't scale.
|
||||
|
||||
|
||||
$r = q("select * from abook where abook_channel = %d",
|
||||
intval($owner)
|
||||
);
|
||||
|
||||
|
||||
if (count($r))
|
||||
$contacts = count($r);
|
||||
// We're checking for 11 to adjust for the abook record for self
|
||||
if ($contacts >= 11)
|
||||
$contactbadge = true;
|
||||
|
||||
|
||||
// Check if an about field in the profile has been created.
|
||||
|
||||
|
||||
$r = q("select * from profile where uid = %d and about <> ''",
|
||||
intval($owner)
|
||||
);
|
||||
|
||||
|
||||
if ($r)
|
||||
$profilebadge = 1;
|
||||
|
||||
|
||||
// Check if keywords have been set
|
||||
|
||||
|
||||
$r = q("select * from profile where uid = %d and keywords <> ''",
|
||||
intval($owner)
|
||||
);
|
||||
|
||||
|
||||
if($r)
|
||||
$keywordsbadge = 1;
|
||||
|
||||
|
||||
return replace_macros(get_markup_template("achievements.tpl"), array(
|
||||
'$newmembertext' => $newmembertext,
|
||||
'$profilebadge' => $profilebadge,
|
||||
'$contactbadge' => $contactbadge,
|
||||
'$keywordsbadge' => $keywordsbadge,
|
||||
'$channelsbadge' => $channelsbadge
|
||||
'$channelsbadge' => null,
|
||||
));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -437,16 +437,14 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
|
||||
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
|
||||
$url = z_root() . '/dirsearch';
|
||||
}
|
||||
|
||||
if(! $url) {
|
||||
} else {
|
||||
$directory = Libzotdir::find_upstream_directory($dirmode);
|
||||
$url = $directory['url'] . '/dirsearch';
|
||||
}
|
||||
|
||||
$token = Config::Get('system','realm_token');
|
||||
|
||||
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
|
||||
$count = (!empty($_REQUEST['count']) ? $_REQUEST['count'] : 100);
|
||||
if($url) {
|
||||
$query = $url . '?f=' . (($token) ? '&t=' . urlencode($token) : '');
|
||||
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
|
||||
|
||||
@@ -23,14 +23,14 @@ class Activity extends Controller {
|
||||
if (! $item_id)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$portable_id = EMPTY_STR;
|
||||
$portable_id = null;
|
||||
|
||||
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
|
||||
dbesc(ACTIVITY_FOLLOW),
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$i = null;
|
||||
|
||||
@@ -166,6 +166,7 @@ class Activity extends Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$portable_id = null;
|
||||
$ob_authorize = false;
|
||||
$item_uid = 0;
|
||||
|
||||
@@ -191,7 +192,7 @@ class Activity extends Controller {
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and item.item_uplink = 0 $item_normal_extra ";
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
@@ -209,7 +210,7 @@ class Activity extends Controller {
|
||||
// Give ocap tokens priority
|
||||
|
||||
if ($ob_authorize) {
|
||||
$sql_extra = " and item.uid = " . intval($token['uid']) . " ";
|
||||
$sql_extra = " and item.uid = " . intval($item_uid) . " ";
|
||||
}
|
||||
else {
|
||||
$sql_extra = item_permissions_sql(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) {
|
||||
|
||||
@@ -8,6 +8,11 @@ class Account_edit {
|
||||
|
||||
function post() {
|
||||
|
||||
// Validate CSRF token
|
||||
//
|
||||
// We terminate with a 403 Forbidden status if the check fails.
|
||||
check_form_security_token_ForbiddenOnErr('admin_account_edit', 'security');
|
||||
|
||||
$account_id = $_REQUEST['aid'];
|
||||
|
||||
if(! $account_id)
|
||||
@@ -18,7 +23,7 @@ class Account_edit {
|
||||
if($pass1 && $pass2 && ($pass1 === $pass2)) {
|
||||
$salt = random_string(32);
|
||||
$password_encoded = hash('whirlpool', $salt . $pass1);
|
||||
$r = q("update account set account_salt = '%s', account_password = '%s',
|
||||
$r = q("update account set account_salt = '%s', account_password = '%s',
|
||||
account_password_changed = '%s' where account_id = %d",
|
||||
dbesc($salt),
|
||||
dbesc($password_encoded),
|
||||
@@ -34,7 +39,7 @@ class Account_edit {
|
||||
$account_level = 5;
|
||||
$account_language = trim($_REQUEST['account_language']);
|
||||
|
||||
$r = q("update account set account_service_class = '%s', account_level = %d, account_language = '%s'
|
||||
$r = q("update account set account_service_class = '%s', account_level = %d, account_language = '%s'
|
||||
where account_id = %d",
|
||||
dbesc($service_class),
|
||||
intval($account_level),
|
||||
@@ -50,11 +55,10 @@ class Account_edit {
|
||||
|
||||
|
||||
function get() {
|
||||
if(argc() > 2)
|
||||
$account_id = argv(2);
|
||||
$account_id = intval(argv(2));
|
||||
|
||||
$x = q("select * from account where account_id = %d limit 1",
|
||||
intval($account_id)
|
||||
$account_id
|
||||
);
|
||||
|
||||
if(! $x) {
|
||||
@@ -62,8 +66,8 @@ class Account_edit {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
$a = replace_macros(get_markup_template('admin_account_edit.tpl'), [
|
||||
'$security' => get_form_security_token('admin_account_edit'),
|
||||
'$account' => $x[0],
|
||||
'$title' => t('Account Edit'),
|
||||
'$pass1' => [ 'pass1', t('New Password'), ' ','' ],
|
||||
|
||||
@@ -6,133 +6,33 @@ use Zotlabs\Lib\Config;
|
||||
|
||||
class Accounts {
|
||||
|
||||
/**
|
||||
* @brief Handle POST actions on accounts admin page.
|
||||
*
|
||||
* This function is called when on the admin user/account page the form was
|
||||
* submitted to handle multiple operations at once. If one of the icons next
|
||||
* to an entry are pressed the function admin_page_accounts() will handle this.
|
||||
*
|
||||
*/
|
||||
|
||||
const MYP = 'ZAR'; // ZAR2x
|
||||
const VERSION = '2.0.0';
|
||||
|
||||
function post() {
|
||||
/**
|
||||
* Handle POST actions on accounts admin page.
|
||||
*/
|
||||
public function post() {
|
||||
|
||||
$pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
|
||||
$users = ( x($_POST, 'user') ? $_POST['user'] : array() );
|
||||
$blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : array() );
|
||||
$pending = x($_POST, 'pending') ? $_POST['pending'] : array();
|
||||
|
||||
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
|
||||
|
||||
$isajax = is_ajax();
|
||||
$rc = 0;
|
||||
|
||||
If (!is_site_admin()) {
|
||||
if ($isajax) {
|
||||
killme();
|
||||
exit;
|
||||
}
|
||||
goaway(z_root() . '/');
|
||||
}
|
||||
|
||||
if ($isajax) {
|
||||
//$debug = print_r($_SESSION[self::MYP],true);
|
||||
$zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
|
||||
? $_POST['zardo'] : '';
|
||||
// zarat arrives with leading underscore _n
|
||||
$zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
|
||||
? substr($_POST['zarat'],1) : '';
|
||||
$zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
|
||||
? hex2bin($_POST['zarse']) : '';
|
||||
|
||||
if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
|
||||
|
||||
//
|
||||
if ($zarop == 'd') {
|
||||
$rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat]),
|
||||
dbesc($_SESSION[self::MYP]['h'][$zarat])
|
||||
);
|
||||
$rc = '×';
|
||||
}
|
||||
elseif ($zarop == 'a') {
|
||||
// approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
|
||||
$rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
|
||||
. " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
|
||||
. " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat]),
|
||||
dbesc($_SESSION[self::MYP]['h'][$zarat])
|
||||
);
|
||||
$rc = 0;
|
||||
$rs = q("SELECT * from register WHERE reg_id = %d ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat])
|
||||
);
|
||||
if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
|
||||
// create account
|
||||
$rc = 'ok'.$rs[0]['reg_id'];
|
||||
$ac = create_account_from_register($rs[0]);
|
||||
if ( $ac['success'] ) {
|
||||
$rc .= '✔';
|
||||
|
||||
$auto_create = Config::Get('system','auto_channel_create',1);
|
||||
|
||||
if($auto_create) {
|
||||
$reonar = json_decode($rs[0]['reg_stuff'], true);
|
||||
// prepare channel creation
|
||||
if($reonar['chan.name'])
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
|
||||
|
||||
if($reonar['chan.did1'])
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
|
||||
|
||||
$permissions_role = Config::Get('system','default_permissions_role');
|
||||
if($permissions_role)
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
|
||||
|
||||
// create channel
|
||||
$new_channel = auto_channel_create($ac['account']['account_id']);
|
||||
|
||||
if($new_channel['success']) {
|
||||
$rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
|
||||
}
|
||||
else {
|
||||
$rc .= ' c ×';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
$rc='oh ×';
|
||||
}
|
||||
}
|
||||
echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
|
||||
}
|
||||
if (is_ajax()) {
|
||||
$this->handle_ajax_request();
|
||||
killme();
|
||||
exit;
|
||||
}
|
||||
|
||||
// change to switch structure?
|
||||
// account block/unblock button was submitted
|
||||
if (x($_POST, 'page_accounts_block')) {
|
||||
for ($i = 0; $i < count($users); $i++) {
|
||||
// if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
|
||||
$op = ($blocked[$i]) ? '& ~' : '| ';
|
||||
q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
|
||||
intval(ACCOUNT_BLOCKED),
|
||||
intval($users[$i])
|
||||
);
|
||||
}
|
||||
notice( sprintf( tt("%s account blocked/unblocked", "%s account blocked/unblocked", count($users)), count($users)) );
|
||||
$this->block_unblock_accounts();
|
||||
}
|
||||
|
||||
// account delete button was submitted
|
||||
if (x($_POST, 'page_accounts_delete')) {
|
||||
foreach ($users as $uid){
|
||||
account_remove($uid, true, false);
|
||||
}
|
||||
notice( sprintf( tt("%s account deleted", "%s accounts deleted", count($users)), count($users)) );
|
||||
$this->delete_accounts();
|
||||
}
|
||||
// registration approved button was submitted
|
||||
if (x($_POST, 'page_accounts_approve')) {
|
||||
@@ -303,7 +203,6 @@ class Accounts {
|
||||
$t = get_markup_template('admin_accounts.tpl');
|
||||
$o = replace_macros($t, array(
|
||||
// strings //
|
||||
'$debug' => $debug,
|
||||
'$title' => t('Administration'),
|
||||
'$page' => t('Accounts'),
|
||||
'$submit' => t('Submit'),
|
||||
@@ -351,5 +250,140 @@ class Accounts {
|
||||
return $o;
|
||||
}
|
||||
|
||||
private function handle_ajax_request(): void {
|
||||
//$debug = print_r($_SESSION[self::MYP],true);
|
||||
$zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
|
||||
? $_POST['zardo'] : '';
|
||||
// zarat arrives with leading underscore _n
|
||||
$zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
|
||||
? substr($_POST['zarat'],1) : '';
|
||||
$zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
|
||||
? hex2bin($_POST['zarse']) : '';
|
||||
|
||||
if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
|
||||
|
||||
$rc = 0;
|
||||
if ($zarop == 'd') {
|
||||
$rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat]),
|
||||
dbesc($_SESSION[self::MYP]['h'][$zarat])
|
||||
);
|
||||
$rc = '×';
|
||||
}
|
||||
elseif ($zarop == 'a') {
|
||||
// approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
|
||||
$rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
|
||||
. " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
|
||||
. " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat]),
|
||||
dbesc($_SESSION[self::MYP]['h'][$zarat])
|
||||
);
|
||||
$rs = q("SELECT * from register WHERE reg_id = %d ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat])
|
||||
);
|
||||
if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
|
||||
// create account
|
||||
$rc = 'ok'.$rs[0]['reg_id'];
|
||||
$ac = create_account_from_register($rs[0]);
|
||||
if ( $ac['success'] ) {
|
||||
$rc .= '✔';
|
||||
|
||||
$auto_create = Config::Get('system','auto_channel_create',1);
|
||||
|
||||
if($auto_create) {
|
||||
$reonar = json_decode($rs[0]['reg_stuff'], true);
|
||||
// prepare channel creation
|
||||
if($reonar['chan.name'])
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
|
||||
|
||||
if($reonar['chan.did1'])
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
|
||||
|
||||
$permissions_role = Config::Get('system','default_permissions_role');
|
||||
if($permissions_role)
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
|
||||
|
||||
// create channel
|
||||
$new_channel = auto_channel_create($ac['account']['account_id']);
|
||||
|
||||
if($new_channel['success']) {
|
||||
$rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
|
||||
}
|
||||
else {
|
||||
$rc .= ' c ×';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
$rc='oh ×';
|
||||
}
|
||||
}
|
||||
echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block or unblock accounts given by the `user` and `blocked` POST params.
|
||||
*
|
||||
* The post params `user` and `blocked` must be present and arrays of equal
|
||||
* lengths. The `user` array should contain account id's or the accounts to
|
||||
* process, and the `blocked` array holds a corresponding boolean value to
|
||||
* indicate that the account at the same offset in the `user` array is or is
|
||||
* not blocked.
|
||||
*
|
||||
* An account that is _not_ blocked will be blocked, and accounts that _are_
|
||||
* blocked will be unblocked.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ShortVariable)
|
||||
*/
|
||||
private function block_unblock_accounts(): void {
|
||||
if (!isset($_POST['user'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$users = $_POST['user'];
|
||||
|
||||
if (!is_array($users)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$xor = db_getfunc('^');
|
||||
|
||||
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 accounts blocked/unblocked", $count);
|
||||
notice(sprintf($fmt, $count));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete multiple accounts given by the `user` POST param.
|
||||
*/
|
||||
private function delete_accounts(): void {
|
||||
if (!isset($_POST['user'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$users = $_POST['user'];
|
||||
|
||||
if (!is_array($users)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($users as $uid){
|
||||
account_remove($uid, true, false);
|
||||
}
|
||||
|
||||
$count = count($users);
|
||||
$fmt = tt("%s account deleted", "%s accounts deleted", $count);
|
||||
notice(sprintf($fmt, $count));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
use App;
|
||||
use \Zotlabs\Lib\Config;
|
||||
use \Zotlabs\Storage\GitRepo;
|
||||
use \Michelf\MarkdownExtra;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Michelf\MarkdownExtra;
|
||||
|
||||
class Addons {
|
||||
|
||||
@@ -24,227 +23,6 @@ class Addons {
|
||||
|
||||
goaway(z_root() . '/admin/addons/' . argv(2) );
|
||||
}
|
||||
elseif(argc() > 2) {
|
||||
switch(argv(2)) {
|
||||
case 'updaterepo':
|
||||
if (array_key_exists('repoName', $_REQUEST)) {
|
||||
$repoName = $_REQUEST['repoName'];
|
||||
}
|
||||
else {
|
||||
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
|
||||
}
|
||||
$extendDir = 'store/[data]/git/sys/extend';
|
||||
$addonDir = $extendDir . '/addon';
|
||||
if (!file_exists($extendDir)) {
|
||||
if (!mkdir($extendDir, 0770, true)) {
|
||||
logger('Error creating extend folder: ' . $extendDir);
|
||||
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
|
||||
}
|
||||
else {
|
||||
if (!symlink(realpath('extend/addon'), $addonDir)) {
|
||||
logger('Error creating symlink to addon folder: ' . $addonDir);
|
||||
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
$repoDir = 'store/[data]/git/sys/extend/addon/' . $repoName;
|
||||
if (!is_dir($repoDir)) {
|
||||
logger('Repo directory does not exist: ' . $repoDir);
|
||||
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
|
||||
}
|
||||
if (!is_writable($repoDir)) {
|
||||
logger('Repo directory not writable to web server: ' . $repoDir);
|
||||
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
|
||||
}
|
||||
$git = new GitRepo('sys', null, false, $repoName, $repoDir);
|
||||
try {
|
||||
if ($git->pull()) {
|
||||
$files = array_diff(scandir($repoDir), array('.', '..'));
|
||||
foreach ($files as $file) {
|
||||
if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
|
||||
$source = '../extend/addon/' . $repoName . '/' . $file;
|
||||
$target = realpath('addon/') . '/' . $file;
|
||||
unlink($target);
|
||||
if (!symlink($source, $target)) {
|
||||
logger('Error linking addons to /addon');
|
||||
json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
json_return_and_die(array('message' => 'Repo updated.', 'success' => true));
|
||||
} else {
|
||||
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
|
||||
}
|
||||
} catch (\PHPGit\Exception\GitException $e) {
|
||||
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
|
||||
}
|
||||
break;
|
||||
case 'removerepo':
|
||||
if (array_key_exists('repoName', $_REQUEST)) {
|
||||
$repoName = $_REQUEST['repoName'];
|
||||
} else {
|
||||
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
|
||||
}
|
||||
$extendDir = 'store/[data]/git/sys/extend';
|
||||
$addonDir = $extendDir . '/addon';
|
||||
if (!file_exists($extendDir)) {
|
||||
if (!mkdir($extendDir, 0770, true)) {
|
||||
logger('Error creating extend folder: ' . $extendDir);
|
||||
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
|
||||
} else {
|
||||
if (!symlink(realpath('extend/addon'), $addonDir)) {
|
||||
logger('Error creating symlink to addon folder: ' . $addonDir);
|
||||
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
$repoDir = 'store/[data]/git/sys/extend/addon/' . $repoName;
|
||||
if (!is_dir($repoDir)) {
|
||||
logger('Repo directory does not exist: ' . $repoDir);
|
||||
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
|
||||
}
|
||||
if (!is_writable($repoDir)) {
|
||||
logger('Repo directory not writable to web server: ' . $repoDir);
|
||||
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
|
||||
}
|
||||
/// @TODO remove directory and unlink /addon/files
|
||||
if (rrmdir($repoDir)) {
|
||||
json_return_and_die(array('message' => 'Repo deleted.', 'success' => true));
|
||||
} else {
|
||||
json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false));
|
||||
}
|
||||
break;
|
||||
case 'installrepo':
|
||||
if (array_key_exists('repoURL', $_REQUEST)) {
|
||||
require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
|
||||
$repoURL = $_REQUEST['repoURL'];
|
||||
$extendDir = 'store/[data]/git/sys/extend';
|
||||
$addonDir = $extendDir . '/addon';
|
||||
if (!file_exists($extendDir)) {
|
||||
if (!mkdir($extendDir, 0770, true)) {
|
||||
logger('Error creating extend folder: ' . $extendDir);
|
||||
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
|
||||
} else {
|
||||
if (!symlink(realpath('extend/addon'), $addonDir)) {
|
||||
logger('Error creating symlink to addon folder: ' . $addonDir);
|
||||
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!is_writable($extendDir)) {
|
||||
logger('Directory not writable to web server: ' . $extendDir);
|
||||
json_return_and_die(array('message' => 'Directory not writable to web server.', 'success' => false));
|
||||
}
|
||||
$repoName = null;
|
||||
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
|
||||
$repoName = $_REQUEST['repoName'];
|
||||
} else {
|
||||
$repoName = GitRepo::getRepoNameFromURL($repoURL);
|
||||
}
|
||||
if (!$repoName) {
|
||||
logger('Invalid git repo');
|
||||
json_return_and_die(array('message' => 'Invalid git repo', 'success' => false));
|
||||
}
|
||||
$repoDir = $addonDir . '/' . $repoName;
|
||||
$tempRepoBaseDir = 'store/[data]/git/sys/temp/';
|
||||
$tempAddonDir = $tempRepoBaseDir . $repoName;
|
||||
|
||||
if (!is_writable($addonDir) || !is_writable($tempAddonDir)) {
|
||||
logger('Temp repo directory or /extend/addon not writable to web server: ' . $tempAddonDir);
|
||||
json_return_and_die(array('message' => 'Temp repo directory not writable to web server.', 'success' => false));
|
||||
}
|
||||
rename($tempAddonDir, $repoDir);
|
||||
|
||||
if (!is_writable(realpath('addon/'))) {
|
||||
logger('/addon directory not writable to web server: ' . $tempAddonDir);
|
||||
json_return_and_die(array('message' => '/addon directory not writable to web server.', 'success' => false));
|
||||
}
|
||||
$files = array_diff(scandir($repoDir), array('.', '..'));
|
||||
foreach ($files as $file) {
|
||||
if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
|
||||
$source = '../extend/addon/' . $repoName . '/' . $file;
|
||||
$target = realpath('addon/') . '/' . $file;
|
||||
unlink($target);
|
||||
if (!symlink($source, $target)) {
|
||||
logger('Error linking addons to /addon');
|
||||
json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
$git = new GitRepo('sys', $repoURL, false, $repoName, $repoDir);
|
||||
$repo = $git->probeRepo();
|
||||
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
|
||||
}
|
||||
break;
|
||||
case 'addrepo':
|
||||
if (array_key_exists('repoURL', $_REQUEST)) {
|
||||
require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
|
||||
$repoURL = $_REQUEST['repoURL'];
|
||||
$extendDir = 'store/[data]/git/sys/extend';
|
||||
$addonDir = $extendDir . '/addon';
|
||||
$tempAddonDir = realpath('store/[data]') . '/git/sys/temp';
|
||||
if (!file_exists($extendDir)) {
|
||||
if (!mkdir($extendDir, 0770, true)) {
|
||||
logger('Error creating extend folder: ' . $extendDir);
|
||||
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
|
||||
} else {
|
||||
if (!symlink(realpath('extend/addon'), $addonDir)) {
|
||||
logger('Error creating symlink to addon folder: ' . $addonDir);
|
||||
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!is_dir($tempAddonDir)) {
|
||||
if (!mkdir($tempAddonDir, 0770, true)) {
|
||||
logger('Error creating temp plugin repo folder: ' . $tempAddonDir);
|
||||
json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false));
|
||||
}
|
||||
}
|
||||
$repoName = null;
|
||||
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
|
||||
$repoName = $_REQUEST['repoName'];
|
||||
} else {
|
||||
$repoName = GitRepo::getRepoNameFromURL($repoURL);
|
||||
}
|
||||
if (!$repoName) {
|
||||
logger('Invalid git repo');
|
||||
json_return_and_die(array('message' => 'Invalid git repo: ' . $repoName, 'success' => false));
|
||||
}
|
||||
$repoDir = $tempAddonDir . '/' . $repoName;
|
||||
if (!is_writable($tempAddonDir)) {
|
||||
logger('Temporary directory for new addon repo is not writable to web server: ' . $tempAddonDir);
|
||||
json_return_and_die(array('message' => 'Temporary directory for new addon repo is not writable to web server.', 'success' => false));
|
||||
}
|
||||
// clone the repo if new automatically
|
||||
$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
|
||||
|
||||
$remotes = $git->git->remote();
|
||||
$fetchURL = $remotes['origin']['fetch'];
|
||||
if ($fetchURL !== $git->url) {
|
||||
if (rrmdir($repoDir)) {
|
||||
$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
|
||||
} else {
|
||||
json_return_and_die(array('message' => 'Error deleting existing addon repo.', 'success' => false));
|
||||
}
|
||||
}
|
||||
$repo = $git->probeRepo();
|
||||
$repo['readme'] = $repo['manifest'] = null;
|
||||
foreach ($git->git->tree('master') as $object) {
|
||||
if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) {
|
||||
$repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash']));
|
||||
} else if ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') {
|
||||
$repo['manifest'] = $git->git->cat->blob($object['hash']);
|
||||
}
|
||||
}
|
||||
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
|
||||
} else {
|
||||
json_return_and_die(array('message' => 'No repo URL provided', 'success' => false));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,37 +186,6 @@ class Addons {
|
||||
|
||||
usort($plugins,'self::plugin_sort');
|
||||
|
||||
$allowManageRepos = false;
|
||||
if(is_writable('extend/addon') && is_writable('store/[data]')) {
|
||||
$allowManageRepos = true;
|
||||
}
|
||||
|
||||
$admin_plugins_add_repo_form= replace_macros(
|
||||
get_markup_template('admin_plugins_addrepo.tpl'), array(
|
||||
'$post' => 'admin/addons/addrepo',
|
||||
'$desc' => t('Enter the public git repository URL of the addon repo.'),
|
||||
'$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''),
|
||||
'$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')),
|
||||
'$submit' => t('Download Addon Repo')
|
||||
)
|
||||
);
|
||||
$newRepoModalID = random_string(3);
|
||||
$newRepoModal = replace_macros(
|
||||
get_markup_template('generic_modal.tpl'), array(
|
||||
'$id' => $newRepoModalID,
|
||||
'$title' => t('Install new repo'),
|
||||
'$ok' => t('Install'),
|
||||
'$cancel' => t('Cancel')
|
||||
)
|
||||
);
|
||||
|
||||
$reponames = $this->listAddonRepos();
|
||||
$addonrepos = [];
|
||||
foreach($reponames as $repo) {
|
||||
$addonrepos[] = array('name' => $repo, 'description' => '');
|
||||
/// @TODO Parse repo info to provide more information about repos
|
||||
}
|
||||
|
||||
$t = get_markup_template('admin_plugins.tpl');
|
||||
return replace_macros($t, array(
|
||||
'$title' => t('Administration'),
|
||||
@@ -449,37 +196,9 @@ class Addons {
|
||||
'$plugins' => $plugins,
|
||||
'$disabled' => t('Disabled - version incompatibility'),
|
||||
'$form_security_token' => get_form_security_token('admin_addons'),
|
||||
'$allowManageRepos' => $allowManageRepos,
|
||||
'$managerepos' => t('Manage Repos'),
|
||||
'$installedtitle' => t('Installed Addon Repositories'),
|
||||
'$addnewrepotitle' => t('Install a New Addon Repository'),
|
||||
'$expandform' => false,
|
||||
'$form' => $admin_plugins_add_repo_form,
|
||||
'$newRepoModal' => $newRepoModal,
|
||||
'$newRepoModalID' => $newRepoModalID,
|
||||
'$addonrepos' => $addonrepos,
|
||||
'$repoUpdateButton' => t('Update'),
|
||||
'$repoBranchButton' => t('Switch branch'),
|
||||
'$repoRemoveButton' => t('Remove')
|
||||
));
|
||||
}
|
||||
|
||||
function listAddonRepos() {
|
||||
$addonrepos = [];
|
||||
$addonDir = 'extend/addon/';
|
||||
if(is_dir($addonDir)) {
|
||||
if ($handle = opendir($addonDir)) {
|
||||
while (false !== ($entry = readdir($handle))) {
|
||||
if ($entry != "." && $entry != "..") {
|
||||
$addonrepos[] = $entry;
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
}
|
||||
return $addonrepos;
|
||||
}
|
||||
|
||||
static public function plugin_sort($a,$b) {
|
||||
return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name'])));
|
||||
}
|
||||
|
||||
@@ -59,14 +59,13 @@ class Features {
|
||||
}
|
||||
|
||||
$tpl = get_markup_template("admin_settings_features.tpl");
|
||||
$o .= replace_macros($tpl, array(
|
||||
|
||||
return replace_macros($tpl, array(
|
||||
'$form_security_token' => get_form_security_token("admin_manage_features"),
|
||||
'$title' => t('Manage Additional Features'),
|
||||
'$features' => $arr,
|
||||
'$submit' => t('Submit'),
|
||||
));
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ class Security {
|
||||
$cloud_disksize = ((x($_POST,'cloud_disksize')) ? 1 : 0);
|
||||
Config::Set('system','cloud_report_disksize',$cloud_disksize);
|
||||
|
||||
$propfind_depth_infinity = ((x($_POST, 'propfind_depth_infinity')) ? 1 : 0);
|
||||
Config::Set('system','propfind_depth_infinity', $propfind_depth_infinity);
|
||||
|
||||
$ws = $this->trim_array_elems(explode("\n",$_POST['whitelisted_sites']));
|
||||
Config::Set('system','whitelisted_sites',$ws);
|
||||
|
||||
@@ -109,6 +112,7 @@ class Security {
|
||||
'$block_public' => array('block_public', t("Block public"), Config::Get('system','block_public'), t("Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated.")),
|
||||
'$cloud_noroot' => [ 'cloud_noroot', t('Provide a cloud root directory'), 1 - intval(Config::Get('system','cloud_disable_siteroot')), t('The cloud root directory lists all channel names which provide public files') ],
|
||||
'$cloud_disksize' => [ 'cloud_disksize', t('Show total disk space available to cloud uploads'), intval(Config::Get('system','cloud_report_disksize')), '' ],
|
||||
'$propfind_depth_infinity' => ['propfind_depth_infinity', t('Allow propfind requests with infinity depth'), intval(Config::Get('system', 'propfind_depth_infinity')), t('Only turn this on if you know what you are doing')],
|
||||
'$transport_security' => array('transport_security', t('Set "Transport Security" HTTP header'),intval(Config::Get('system','transport_security_header')),''),
|
||||
'$content_security' => array('content_security', t('Set "Content Security Policy" HTTP header'),intval(Config::Get('system','content_security_policy')),''),
|
||||
'$allowed_email' => array('allowed_email', t("Allowed email domains"), Config::Get('system','allowed_email'), t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")),
|
||||
|
||||
@@ -6,6 +6,8 @@ use Zotlabs\Lib\Config;
|
||||
|
||||
class Site {
|
||||
|
||||
private string $eol;
|
||||
private string $joo;
|
||||
|
||||
/**
|
||||
* @brief POST handler for Admin Site Page.
|
||||
@@ -208,7 +210,6 @@ class Site {
|
||||
//Config::Set('system','force_queue_threshold', $force_queue);
|
||||
|
||||
Config::Set('system','no_community_page', $no_community_page);
|
||||
Config::Set('system','no_utf', $no_utf);
|
||||
|
||||
Config::Set('system','sse_enabled', $sse_enabled);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
use \Michelf\MarkdownExtra;
|
||||
use Michelf\MarkdownExtra;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
/**
|
||||
|
||||
@@ -108,6 +108,9 @@ class Api extends \Zotlabs\Web\Controller {
|
||||
|
||||
echo api_call();
|
||||
killme();
|
||||
|
||||
// not reached
|
||||
return;
|
||||
}
|
||||
|
||||
function oauth_get_client($request){
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use \Zotlabs\Lib as Zlib;
|
||||
use Zotlabs\Lib as Zlib;
|
||||
|
||||
class Apporder extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -25,13 +25,16 @@ class Apporder extends \Zotlabs\Web\Controller {
|
||||
$syslist[] = Zlib\Apps::app_encode($li);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zlib\Apps::translate_system_apps($syslist);
|
||||
|
||||
usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
|
||||
|
||||
$syslist = Zlib\Apps::app_order(local_channel(),$syslist, $l);
|
||||
|
||||
$navbar_apps = [];
|
||||
$nav_apps = [];
|
||||
|
||||
foreach($syslist as $app) {
|
||||
if($l === 'nav_pinned_app') {
|
||||
$navbar_apps[] = Zlib\Apps::app_render($app,'nav-order-pinned');
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use \Zotlabs\Lib\Config;
|
||||
use \Zotlabs\Lib as Zlib;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib as Zlib;
|
||||
|
||||
class Apps extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
@@ -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,';
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user