mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 09:01:15 -04:00
Compare commits
2074 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b13055dfe | ||
|
|
06afd8a375 | ||
|
|
6f027544d6 | ||
|
|
ebab5ff281 | ||
|
|
5fb6e5d6f7 | ||
|
|
5a84ffdcda | ||
|
|
ad993645be | ||
|
|
0701cde239 | ||
|
|
a136c288d5 | ||
|
|
1624a2620a | ||
|
|
f4769d0f04 | ||
|
|
c8e30a00e2 | ||
|
|
169c971cb1 | ||
|
|
51745d3652 | ||
|
|
3ebbb91ae9 | ||
|
|
762d402dea | ||
|
|
051cef79fc | ||
|
|
b05a440f03 | ||
|
|
9bb4988eda | ||
|
|
f66f0e398b | ||
|
|
49cb73c8c7 | ||
|
|
2a00bd9a28 | ||
|
|
553b3f6faa | ||
|
|
2980827925 | ||
|
|
45a78dcbc0 | ||
|
|
5813b65aed | ||
|
|
f8acd1d3a5 | ||
|
|
c9ebb23b69 | ||
|
|
bc998eacd0 | ||
|
|
648979467a | ||
|
|
5c0ff6f584 | ||
|
|
632721da4e | ||
|
|
f3a702e927 | ||
|
|
58985f2200 | ||
|
|
c55662510d | ||
|
|
f01e917fff | ||
|
|
3940187d19 | ||
|
|
1215e8a030 | ||
|
|
5b6e27233a | ||
|
|
b80cba4e68 | ||
|
|
f2b28f5bbb | ||
|
|
4aeb4963a4 | ||
|
|
de9b10e850 | ||
|
|
36a1d98c52 | ||
|
|
cf66f245b4 | ||
|
|
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 | ||
|
|
91baa52b8b | ||
|
|
5338793883 | ||
|
|
9acc73b273 | ||
|
|
c626985448 | ||
|
|
5cfb3842f1 | ||
|
|
25b089c1a9 | ||
|
|
67a9292aaa | ||
|
|
81dda15669 | ||
|
|
5b7f8d986c | ||
|
|
5dee600735 | ||
|
|
01da60b385 | ||
|
|
951800eca6 | ||
|
|
72c47cd8db | ||
|
|
e3a8668c32 | ||
|
|
fd9977eada | ||
|
|
bd3304ff94 | ||
|
|
586cda5155 | ||
|
|
c9a8914b07 | ||
|
|
b21b9260d9 | ||
|
|
b5c07e4c01 | ||
|
|
28b5b0cab5 | ||
|
|
39d0a3f1f6 | ||
|
|
513cd3b99a | ||
|
|
ce9d67f7b1 | ||
|
|
8268ed1ba7 | ||
|
|
6c1d0851d7 | ||
|
|
3bc0fd5db4 | ||
|
|
4c3f3d1477 | ||
|
|
17411a501c | ||
|
|
d446f171c5 | ||
|
|
b24b409a01 | ||
|
|
3791dfab3a | ||
|
|
31a146b23a | ||
|
|
e52714ed16 | ||
|
|
2c17d0b031 | ||
|
|
57e69372d3 | ||
|
|
43acb86aab | ||
|
|
e339fbcc46 | ||
|
|
f05b8bd87d | ||
|
|
4e6696b049 | ||
|
|
fbc79e36e0 | ||
|
|
c9d4b068c2 | ||
|
|
b6dbbbc82f | ||
|
|
954d92c354 | ||
|
|
8dbebc2b42 | ||
|
|
14207c68ca | ||
|
|
0ed08274f1 | ||
|
|
2a152e0803 | ||
|
|
a0c54c5f04 | ||
|
|
ac8c80ddbe | ||
|
|
ebad9d56c9 | ||
|
|
0481901b59 | ||
|
|
0534fe6886 | ||
|
|
6e51571309 | ||
|
|
fe30b54975 | ||
|
|
b00ae997a5 | ||
|
|
b5b7d0cda9 | ||
|
|
300d461a1a | ||
|
|
e516c1352f | ||
|
|
4b4cac63fd | ||
|
|
47f109451d | ||
|
|
e466c73407 | ||
|
|
17183cc5dc | ||
|
|
e5aae2af0f | ||
|
|
939e5d9ca5 | ||
|
|
600209e21e | ||
|
|
173c4d242d | ||
|
|
76b8c36f7c | ||
|
|
12c88c06d8 | ||
|
|
f35352090e | ||
|
|
e5db47e0d5 | ||
|
|
6a52e502aa | ||
|
|
6a866fe904 | ||
|
|
229efddbf1 | ||
|
|
abb67a4565 | ||
|
|
2e324d4cef | ||
|
|
d4d1a7523d | ||
|
|
d9d239bf3a | ||
|
|
429d15f009 | ||
|
|
7a3f2c1ba9 | ||
|
|
9f473fc204 | ||
|
|
35a05073f2 | ||
|
|
472484dde0 | ||
|
|
5c3bdbd1e0 | ||
|
|
ec02453d37 | ||
|
|
2b44be58c3 | ||
|
|
c44db397ff | ||
|
|
a385fdff37 | ||
|
|
20aacb82c6 | ||
|
|
0d17d8dad9 | ||
|
|
2ab0118c13 | ||
|
|
30419bdbf6 | ||
|
|
21b60bf119 | ||
|
|
5db3f93be9 | ||
|
|
d25314c75b | ||
|
|
e20327d267 | ||
|
|
8ab3ad6531 | ||
|
|
bf008465ad | ||
|
|
a29a1c768d | ||
|
|
90bc987ea7 | ||
|
|
46fdce4402 | ||
|
|
38c947590e | ||
|
|
c5faa012b5 | ||
|
|
2f0a47e583 | ||
|
|
c958cc6f90 | ||
|
|
541a0f6476 | ||
|
|
065f85bab1 | ||
|
|
38ac60e618 | ||
|
|
160c40b580 | ||
|
|
005d4ad351 | ||
|
|
90a1dad02c | ||
|
|
4daba84223 | ||
|
|
fc182f1b07 | ||
|
|
23a19ecf1f | ||
|
|
0207c02420 | ||
|
|
68135c28da | ||
|
|
274bfa9024 | ||
|
|
4bb28a21c4 | ||
|
|
8b75f50f23 | ||
|
|
0e50b1d10c | ||
|
|
8f4c3a2f88 | ||
|
|
73006ccdf5 | ||
|
|
1006ebbf61 | ||
|
|
436b1673cf | ||
|
|
e530476e6c | ||
|
|
e0a91bed7a | ||
|
|
168ec53686 | ||
|
|
4d1be3aea5 | ||
|
|
e8f816a981 | ||
|
|
e649ba5b13 | ||
|
|
92ce66e766 | ||
|
|
96210f5ecc | ||
|
|
1411eafa9b | ||
|
|
20db45c815 | ||
|
|
4acdb8fb10 | ||
|
|
9e9e8efb2d | ||
|
|
f4495fd441 | ||
|
|
e2ae8f0c4d | ||
|
|
074dc440cc | ||
|
|
e9dc4b553b | ||
|
|
d7fa6f6709 | ||
|
|
40a9989be2 | ||
|
|
d1648927b5 | ||
|
|
ecde4a3ded | ||
|
|
687cda3673 | ||
|
|
47cdef390a | ||
|
|
05a5b644bf | ||
|
|
84556854e8 | ||
|
|
314443d41e | ||
|
|
c23a71c936 | ||
|
|
12b33a23de | ||
|
|
a305c20e08 | ||
|
|
c70bd08c10 | ||
|
|
e2cfe245b7 | ||
|
|
12b24e0e5e | ||
|
|
d5291e9b07 | ||
|
|
a1818b1a29 | ||
|
|
e8eb283fd8 | ||
|
|
96d5370122 | ||
|
|
2bcb6a4fed | ||
|
|
aee396421a | ||
|
|
897568a087 | ||
|
|
69109a558b | ||
|
|
4aff6d19d6 | ||
|
|
a5c1b669b4 | ||
|
|
3cb5d14037 | ||
|
|
5f685bcf63 | ||
|
|
cb44f7e360 | ||
|
|
2aee659cbd | ||
|
|
b117cf9dc7 | ||
|
|
c2ce1d9881 | ||
|
|
2ed8908127 | ||
|
|
6588e272db | ||
|
|
c13645f136 | ||
|
|
8cee16be1b | ||
|
|
45c0091d3d | ||
|
|
44232677c8 | ||
|
|
16603ca854 | ||
|
|
75184355d0 | ||
|
|
1988d21e6c | ||
|
|
bccac55cf9 | ||
|
|
19eeadfe5b | ||
|
|
8f74ee67e3 | ||
|
|
b0a11537de | ||
|
|
2693e9e990 | ||
|
|
04741c761a | ||
|
|
4de9cb1142 | ||
|
|
8f890fb6fa | ||
|
|
158ddfb009 | ||
|
|
2b4f344181 | ||
|
|
1afb2a4ce8 | ||
|
|
2e5f922561 | ||
|
|
a6498a0cfc | ||
|
|
8ffab25f5d | ||
|
|
1073392398 | ||
|
|
7d41deebce | ||
|
|
76064dbb33 | ||
|
|
7e48caae6b | ||
|
|
afbeb58c16 | ||
|
|
1ab4f36a1b | ||
|
|
cea9c88b9e | ||
|
|
babe118383 | ||
|
|
2b140e53cc | ||
|
|
9008760aa6 | ||
|
|
fb1514a782 | ||
|
|
7679894684 | ||
|
|
520cf1015c | ||
|
|
64bd8eef4b | ||
|
|
aa42f6a6b2 | ||
|
|
13345d3cbe | ||
|
|
888ee16d52 | ||
|
|
0f3e01f343 | ||
|
|
79220ede66 | ||
|
|
6b98b799c8 | ||
|
|
9f49d313f5 | ||
|
|
a5f0253aef | ||
|
|
4e6f871bc4 | ||
|
|
803cd74b48 | ||
|
|
0bfdb958f5 | ||
|
|
becd4c6ffd | ||
|
|
3f411787c1 | ||
|
|
5782a674b0 | ||
|
|
fc79e47d88 | ||
|
|
1c45030c58 | ||
|
|
18f3887050 | ||
|
|
2cc962e53a | ||
|
|
5b93aa1148 | ||
|
|
4daa03f025 | ||
|
|
8ae9df3bb7 | ||
|
|
25d9d3ba1b | ||
|
|
26ce231951 | ||
|
|
fb9464437e | ||
|
|
4dff1a1e5b | ||
|
|
b498e50f74 | ||
|
|
2c05638776 | ||
|
|
5cbd42bbc4 | ||
|
|
ac6720e118 | ||
|
|
8c87b06caa | ||
|
|
339e702beb | ||
|
|
8750c5f7bc | ||
|
|
5281f4dd9b | ||
|
|
c3b4397ea3 | ||
|
|
c12ef4fbf4 | ||
|
|
424b31b7f0 | ||
|
|
20ee1a5b5b | ||
|
|
2cd779cbe9 | ||
|
|
a3f1189df7 | ||
|
|
2bc088e555 | ||
|
|
67d8b977b6 | ||
|
|
5b1e532791 | ||
|
|
0e1bf2cef0 | ||
|
|
4f129e05e5 | ||
|
|
3733a80c1d | ||
|
|
220571d2a9 | ||
|
|
f6b9a1dd3c | ||
|
|
393d5020f8 | ||
|
|
06ac41c005 | ||
|
|
39ee872f49 | ||
|
|
a7c51f5d65 | ||
|
|
5309c032db | ||
|
|
176298ffeb | ||
|
|
fdf19e659e | ||
|
|
e799589781 | ||
|
|
10acf90d06 | ||
|
|
b184533115 | ||
|
|
b50e06a9d9 | ||
|
|
66901dbe3e | ||
|
|
4a7879aad2 | ||
|
|
30aa0e3822 | ||
|
|
cadc7ee29e | ||
|
|
5a44b8c40c | ||
|
|
487e68ebd1 | ||
|
|
6cdbc28d79 | ||
|
|
4113bea104 | ||
|
|
294359d7f5 | ||
|
|
8ff870482f | ||
|
|
56cb6f1034 | ||
|
|
7eb23aa8b8 | ||
|
|
c793cea2f0 | ||
|
|
4e19f1c8be | ||
|
|
3d3fcd7334 | ||
|
|
61c03e4b4e | ||
|
|
dd0be272d0 | ||
|
|
b781739949 | ||
|
|
2221d8dd12 | ||
|
|
d67a0b14e3 | ||
|
|
b838632318 | ||
|
|
8c38466b75 | ||
|
|
2919b36e91 | ||
|
|
52f7b508af | ||
|
|
15f6bc93cf | ||
|
|
8c4269d037 | ||
|
|
7394c97f23 | ||
|
|
33e45d98a3 | ||
|
|
241cc1ad63 | ||
|
|
b26db5bde6 | ||
|
|
9be799de15 | ||
|
|
014737fe21 | ||
|
|
d3093dce1b | ||
|
|
61f9ad8274 | ||
|
|
7067a0adc2 | ||
|
|
eb8cab37f3 | ||
|
|
467e0b32b4 | ||
|
|
204d91c3c3 | ||
|
|
1bd52867fb | ||
|
|
898fb4f800 | ||
|
|
63a01c0214 | ||
|
|
39933052a9 | ||
|
|
719dbf091a | ||
|
|
2dad3a8fe5 | ||
|
|
d99ba64206 | ||
|
|
202b797fe6 | ||
|
|
9df96fa03b | ||
|
|
7afb01e488 | ||
|
|
ae140465d7 | ||
|
|
475cbf6510 | ||
|
|
39e5e29ce5 | ||
|
|
f4ffef967a | ||
|
|
77a6a21ea2 | ||
|
|
4e35d34226 | ||
|
|
3708896a65 | ||
|
|
7c3f28f9d2 | ||
|
|
afc8b88933 | ||
|
|
4668178dee | ||
|
|
bfec7b6901 | ||
|
|
f026afe11c | ||
|
|
f388fcaf08 | ||
|
|
9bd2b3ab17 | ||
|
|
2d0b216a2c | ||
|
|
c5bca0279c | ||
|
|
3fca63a15f | ||
|
|
c47900f366 | ||
|
|
84f64214c3 | ||
|
|
9cd01e2e13 | ||
|
|
841b4f7d81 | ||
|
|
70212cdb59 | ||
|
|
5f77e9f4ce | ||
|
|
6276f36b90 | ||
|
|
2461e709d2 | ||
|
|
1055718935 | ||
|
|
82f69018a6 | ||
|
|
c22f633ae0 | ||
|
|
c71eb401c0 | ||
|
|
5a1079750e | ||
|
|
3d03c24f06 | ||
|
|
983fc84f28 | ||
|
|
1861eeeb0a | ||
|
|
663aeca2a7 | ||
|
|
526730672a | ||
|
|
7f292d4765 | ||
|
|
99bff67168 | ||
|
|
bb3caeb629 | ||
|
|
65185a70d5 | ||
|
|
6d1f34284b | ||
|
|
2cfdbbd956 | ||
|
|
5f66ad5bc5 | ||
|
|
aff11443b4 | ||
|
|
6ced7ecf89 | ||
|
|
2d467a15ba | ||
|
|
28c8229218 | ||
|
|
0bcecc4baa | ||
|
|
78e68519e8 | ||
|
|
d2b06995c7 | ||
|
|
5cbae0fb81 | ||
|
|
2ddc087512 | ||
|
|
b0fe94b4b3 | ||
|
|
45275910e6 | ||
|
|
c04e781926 | ||
|
|
09a609ef6b | ||
|
|
213ee83a92 | ||
|
|
db5e524e3c | ||
|
|
f882c44fb3 | ||
|
|
8f9e9116df | ||
|
|
04a35dac9a | ||
|
|
ed03befa02 | ||
|
|
f944f46744 | ||
|
|
3f5c45a567 | ||
|
|
464149e22d | ||
|
|
b51ed67efb | ||
|
|
30ba0661aa | ||
|
|
afdc3d6d18 | ||
|
|
26cb32612d | ||
|
|
6a710c3cc3 | ||
|
|
7028e07535 | ||
|
|
6666bdfda9 | ||
|
|
3e57f150bc | ||
|
|
a50b3181ad | ||
|
|
de992452ee | ||
|
|
4cddc3d0df | ||
|
|
241d96e9fa | ||
|
|
8ae6e785f3 | ||
|
|
1c34c354cf | ||
|
|
0f02553d12 | ||
|
|
3f5cfc8fa2 | ||
|
|
0097840e32 | ||
|
|
082b615e50 | ||
|
|
62cbd87e71 | ||
|
|
72453c49f8 | ||
|
|
66ea277045 | ||
|
|
40a93d92c8 | ||
|
|
7df701b434 | ||
|
|
d760790643 | ||
|
|
1ed8383c33 | ||
|
|
d139f2fe87 | ||
|
|
20a8da0683 | ||
|
|
ff018b975b | ||
|
|
fcd657040e | ||
|
|
605f982520 | ||
|
|
fb1c66fbc9 | ||
|
|
d02fa7c268 | ||
|
|
5abe14982a | ||
|
|
8be9b109fd | ||
|
|
91147d5c5b | ||
|
|
08d4bd94fa | ||
|
|
76a92ac2e1 | ||
|
|
7c688de9cd | ||
|
|
93a45be181 | ||
|
|
d187c0025a | ||
|
|
4e9432263a | ||
|
|
0d4c3fd215 | ||
|
|
62aefadc27 | ||
|
|
6e0d0e3832 | ||
|
|
798e870e71 | ||
|
|
6a63a38e8d | ||
|
|
9199a1ba81 | ||
|
|
ac1e20b188 | ||
|
|
ad9fb4d530 | ||
|
|
ffc2455bea | ||
|
|
0a818191c1 | ||
|
|
c7ec3159ea | ||
|
|
4d5a7ec39f | ||
|
|
13c074f8b8 | ||
|
|
088a87914f | ||
|
|
5110dcb912 | ||
|
|
64748cf1f1 | ||
|
|
4ba4b2976e | ||
|
|
06183ba01a | ||
|
|
539ae37553 | ||
|
|
8f41d170a5 | ||
|
|
d9e97a7c1f | ||
|
|
51fe071c5e | ||
|
|
c5cab3004f | ||
|
|
9c62514c1b | ||
|
|
0428a97e00 | ||
|
|
43a2c21d87 | ||
|
|
69862bc6df | ||
|
|
388e7c88df | ||
|
|
9348bd6ea5 | ||
|
|
0c1d0f7498 | ||
|
|
81ba070e1a | ||
|
|
a7812657f1 | ||
|
|
bd5f77dbeb | ||
|
|
d862a6f075 | ||
|
|
18725c47a0 | ||
|
|
59b8c8ad48 | ||
|
|
494ff44a69 | ||
|
|
5efc6bdd2f | ||
|
|
4835758293 | ||
|
|
d0bb3a7354 | ||
|
|
14df925aa6 | ||
|
|
350f84913a | ||
|
|
78ab2e33ef | ||
|
|
75e1b70584 | ||
|
|
1dc73935d9 | ||
|
|
7d7b43c5b9 | ||
|
|
a4d63ab9a3 | ||
|
|
c009c5f43a | ||
|
|
9d56bb952e | ||
|
|
84abf28cec | ||
|
|
cad82d12d2 | ||
|
|
1846ed75bf | ||
|
|
0a6bb06f86 | ||
|
|
a10402a788 | ||
|
|
5da0cc138f | ||
|
|
2145207ad2 | ||
|
|
f086dfd8ca | ||
|
|
26cfc29303 | ||
|
|
10d1cbd3ce | ||
|
|
1299fdb7be | ||
|
|
430347a295 | ||
|
|
960354b16c | ||
|
|
481e08b904 | ||
|
|
76ce4705e2 | ||
|
|
7a5bb99d87 | ||
|
|
11d7a4c9f7 | ||
|
|
9dd63db736 | ||
|
|
f74922db39 | ||
|
|
605aa37ad3 | ||
|
|
262cebb568 | ||
|
|
bfa81490c1 | ||
|
|
219f0dfeca | ||
|
|
3a50a0b715 | ||
|
|
b25662e183 | ||
|
|
47a86f8771 | ||
|
|
07696d4bd1 | ||
|
|
52e97fe115 | ||
|
|
58033f3255 | ||
|
|
ba4773a61e | ||
|
|
977e6a02f4 | ||
|
|
6a53ddef21 | ||
|
|
2fb9c0ec0d | ||
|
|
98c3e2f93f | ||
|
|
fb4568001d | ||
|
|
5eab32a65b | ||
|
|
483221e2a8 | ||
|
|
2e575dee52 | ||
|
|
058c7d6c13 | ||
|
|
630cecd740 | ||
|
|
4d29cffde5 | ||
|
|
c6116e367a | ||
|
|
b6e6cecf70 | ||
|
|
ce15852b9a | ||
|
|
7c34a3676d | ||
|
|
1c92c7476b | ||
|
|
80e124f53e | ||
|
|
48cec94505 | ||
|
|
26c1fa07c9 | ||
|
|
78a6774206 | ||
|
|
3b812f2570 | ||
|
|
2e15207d0b | ||
|
|
716013633e | ||
|
|
1ca91c49aa | ||
|
|
7de629a8c3 | ||
|
|
592359ef49 | ||
|
|
a56d727c26 | ||
|
|
0b2781f42e | ||
|
|
b5223a4efb | ||
|
|
fe43e0994f | ||
|
|
d71c2c245f | ||
|
|
f85d2d3423 | ||
|
|
3859c010f0 | ||
|
|
526729c0f1 | ||
|
|
1cd3369f6a | ||
|
|
418b1eaf78 | ||
|
|
c26ae553e6 | ||
|
|
e0ac7b7f9f | ||
|
|
8d78698d00 | ||
|
|
d5c189753a | ||
|
|
9861e7a0c4 | ||
|
|
6d5fa9205c | ||
|
|
0fee7804fb | ||
|
|
80d1e07908 | ||
|
|
f72f5c7321 | ||
|
|
a5d483fb5d | ||
|
|
26a7cef0d8 | ||
|
|
53354a1930 | ||
|
|
c052b7fa99 | ||
|
|
9ecd38911e | ||
|
|
4002dbaa8b | ||
|
|
57e32a7912 | ||
|
|
b6a72d6e4e | ||
|
|
6e592ed200 | ||
|
|
637f39f282 | ||
|
|
842df8a799 | ||
|
|
6c033fc776 | ||
|
|
2ff84ab25a | ||
|
|
01c6fd03b7 | ||
|
|
b139e5bb00 | ||
|
|
7c4362db53 | ||
|
|
3c0d6339bb | ||
|
|
a0cfe22501 | ||
|
|
0dc959d9fe | ||
|
|
f7bf9ede72 | ||
|
|
ecdd9a4d6e | ||
|
|
1aeb05628b | ||
|
|
b464fae3bf | ||
|
|
a34ce0732d | ||
|
|
f457b6623d | ||
|
|
01ebd51fb2 | ||
|
|
cb25fc031b | ||
|
|
6c6fc82f43 | ||
|
|
990017b588 | ||
|
|
192ab22cda | ||
|
|
5e5a0d7c91 | ||
|
|
2dc1adf091 | ||
|
|
371b8440c3 | ||
|
|
49509e7347 | ||
|
|
66f5b34c07 | ||
|
|
6a3d372050 | ||
|
|
c95359024c | ||
|
|
edf898d7b7 | ||
|
|
ee0060619d | ||
|
|
4f8ede35bd | ||
|
|
9d9c102da8 | ||
|
|
3de8f5e7de | ||
|
|
a18e873d08 | ||
|
|
b3c260a145 | ||
|
|
1097bcdaf9 | ||
|
|
cfde1be097 | ||
|
|
6df4da5313 | ||
|
|
f910de849f | ||
|
|
d6eaeba239 | ||
|
|
5c2e10c01e | ||
|
|
8754f72e63 | ||
|
|
569f243ebd | ||
|
|
651a3f8380 | ||
|
|
40714ecdd0 | ||
|
|
d4b1bcd641 | ||
|
|
acc1834b0d | ||
|
|
e237cf226a | ||
|
|
7c5a0887cc | ||
|
|
0745d0616a | ||
|
|
9cbb9a4874 | ||
|
|
14f3b72c82 | ||
|
|
b05845f495 | ||
|
|
2114779037 | ||
|
|
937b6d360e | ||
|
|
0d30eed4a7 | ||
|
|
39d4f67417 | ||
|
|
68d989c79e | ||
|
|
9600789d6b | ||
|
|
ea7559c158 | ||
|
|
baa12b7497 | ||
|
|
ac4aa6a9ea | ||
|
|
732dbfd6f5 | ||
|
|
5860abf46f | ||
|
|
2874d3e1e1 | ||
|
|
42b0205ad0 | ||
|
|
36778850ee | ||
|
|
19c0e97658 | ||
|
|
fe018d646a | ||
|
|
24132e56d9 | ||
|
|
8fc0210428 | ||
|
|
64560cbca9 | ||
|
|
6e97c97920 | ||
|
|
916edcb45e | ||
|
|
8873c10364 | ||
|
|
77e1220cf9 | ||
|
|
f402baffd3 | ||
|
|
216f3755fc | ||
|
|
d846cefade | ||
|
|
f3efdbf230 | ||
|
|
826ef11247 | ||
|
|
b68ddc4cd3 | ||
|
|
41f909c415 | ||
|
|
0b4e086376 | ||
|
|
5af3c35778 | ||
|
|
dddcddc453 | ||
|
|
754d90a676 | ||
|
|
8b0dce56ad | ||
|
|
42696606e3 | ||
|
|
b645ede168 | ||
|
|
6e12b5ec08 | ||
|
|
fbf36992be | ||
|
|
e0de813700 | ||
|
|
39448a0871 | ||
|
|
4fb37ef6f3 | ||
|
|
a9d4adaf23 | ||
|
|
70dfce356b | ||
|
|
10fbfa06e9 | ||
|
|
6315757967 | ||
|
|
9ddd840897 | ||
|
|
6c5627ac0e | ||
|
|
c2d6d376a4 | ||
|
|
55532c7cb1 | ||
|
|
a93fed5ae2 | ||
|
|
ba1b48f177 | ||
|
|
898762dd95 | ||
|
|
81ce67df94 | ||
|
|
55097c47c5 | ||
|
|
97b82fc77b | ||
|
|
b7bda0b87d | ||
|
|
6bf61dfa6b | ||
|
|
0e59cfb839 | ||
|
|
328ce0a837 | ||
|
|
34e24ea5e9 | ||
|
|
907426af5e | ||
|
|
360713c689 | ||
|
|
ee8aba3221 | ||
|
|
ae657754b0 | ||
|
|
0a730935f5 | ||
|
|
d285da09fe | ||
|
|
b291f1bad3 | ||
|
|
e1b660bfa3 | ||
|
|
0036c0cde9 | ||
|
|
49c1833a46 | ||
|
|
46fa26502b | ||
|
|
ba1e705c61 | ||
|
|
043e2ff58b | ||
|
|
deba1863f5 | ||
|
|
0e27f010f9 | ||
|
|
45b1be8962 | ||
|
|
fe9ca30c5e | ||
|
|
9e8ba5f6e2 | ||
|
|
5207e1e774 | ||
|
|
c1228d6b6d | ||
|
|
6262d351b7 | ||
|
|
27e57ff7aa | ||
|
|
74fc7508f3 | ||
|
|
3eea4f475c | ||
|
|
37b22fe542 | ||
|
|
b5b8106e7a | ||
|
|
b77100ff6d | ||
|
|
5eb6572277 | ||
|
|
69bed9c889 | ||
|
|
3c88c5e66a | ||
|
|
d40d62ac4f | ||
|
|
d23ed6b11f | ||
|
|
1e2a4a57b6 | ||
|
|
7892eeb2d2 | ||
|
|
d7ceb977da | ||
|
|
36d0594b8e | ||
|
|
3f32a5239d | ||
|
|
15a7d2d4de | ||
|
|
80ed2ff89a | ||
|
|
37a0343163 | ||
|
|
8529e2f14e | ||
|
|
b73401bd7f | ||
|
|
af839a0589 | ||
|
|
4bbeb224f6 | ||
|
|
8435d9eb13 | ||
|
|
d97df1859f | ||
|
|
46f67eaa1e | ||
|
|
54451851bb | ||
|
|
5b7387459c | ||
|
|
5d64a9c90f | ||
|
|
ffaa985339 | ||
|
|
291e12574a | ||
|
|
fc5b5ba021 | ||
|
|
056c55a963 | ||
|
|
02a0af3eef | ||
|
|
96e8316633 | ||
|
|
37878bf0a3 | ||
|
|
b4f079c4b5 | ||
|
|
18abfb11ef | ||
|
|
25dbc8a9f6 | ||
|
|
c639704f3c | ||
|
|
3dd7394247 | ||
|
|
b860b730a9 | ||
|
|
17e2877c91 | ||
|
|
b7bc28c333 | ||
|
|
fb5a52cbde | ||
|
|
6d125d02d8 | ||
|
|
0b18b35f5f | ||
|
|
9859008271 | ||
|
|
423c36f67b | ||
|
|
1e0195e439 | ||
|
|
30271bb32f | ||
|
|
e2b1670d6c | ||
|
|
2bfdfbe3cc | ||
|
|
9a85421a0e | ||
|
|
1fa59df6f3 | ||
|
|
2c93294eea | ||
|
|
316829269a | ||
|
|
55236f86e0 | ||
|
|
060210e930 | ||
|
|
9291622885 | ||
|
|
07978a061e | ||
|
|
08b2356ed1 | ||
|
|
d17934ed80 | ||
|
|
94f17f0dae | ||
|
|
7ccb2a2615 | ||
|
|
067a66b927 | ||
|
|
096fad5e8c | ||
|
|
e21e4c7127 | ||
|
|
5754ea828d | ||
|
|
5fbc203367 | ||
|
|
08884c44fb | ||
|
|
bd04ca21a4 | ||
|
|
19ae8cfdfc | ||
|
|
86e953f495 | ||
|
|
4bc4f5b2a6 | ||
|
|
5f2e808497 | ||
|
|
4f69e02768 | ||
|
|
e6ce2885c0 | ||
|
|
ec19ee9d82 | ||
|
|
983f063d33 | ||
|
|
eb6a143fff | ||
|
|
1881029040 | ||
|
|
209651705d | ||
|
|
fab3c92a7c | ||
|
|
8ad7376865 | ||
|
|
c41831aff9 | ||
|
|
8515aa6966 | ||
|
|
691de5bf2e | ||
|
|
2e155892fe | ||
|
|
6680c2faf3 | ||
|
|
decc8f2162 | ||
|
|
7d7a0c160f | ||
|
|
e89563eb4c | ||
|
|
dd204ec34f | ||
|
|
b3a5dd8aa8 | ||
|
|
26ee56f39c | ||
|
|
300b0e27bd | ||
|
|
29489f62cf | ||
|
|
09465619e5 | ||
|
|
390af7722d | ||
|
|
e18157f818 | ||
|
|
5435d2881c | ||
|
|
2e8f3d1869 | ||
|
|
3ad1cab006 | ||
|
|
b806a3ccc2 | ||
|
|
5e780ba089 | ||
|
|
c0a7dfe2f6 | ||
|
|
fe50d78a0f | ||
|
|
e513950cb5 | ||
|
|
adc6390a22 | ||
|
|
9449e8bd61 | ||
|
|
f13af0f60b | ||
|
|
acdb773f89 | ||
|
|
651a288148 | ||
|
|
b0664f7349 | ||
|
|
51586037e1 | ||
|
|
f573c1772a | ||
|
|
f08e91e19d | ||
|
|
8cd9fff26a | ||
|
|
d489a2854e | ||
|
|
9cfd1c2318 | ||
|
|
2dd0677d23 | ||
|
|
00d403e729 | ||
|
|
d83e2daf36 | ||
|
|
8fe6aede03 | ||
|
|
fa4ab45692 | ||
|
|
f57fbaa5dd | ||
|
|
aba8002170 | ||
|
|
9cc85adf47 | ||
|
|
01ed001041 | ||
|
|
403539919a | ||
|
|
52ea2fa33e | ||
|
|
ecd4754f6d | ||
|
|
f71033b30d | ||
|
|
885068834f | ||
|
|
c4c4ab2f3d | ||
|
|
aec3247952 | ||
|
|
b05b756148 | ||
|
|
03819abb22 | ||
|
|
d074e2aba0 | ||
|
|
2bbecfe8dd | ||
|
|
e078e13325 | ||
|
|
9d3b852d38 | ||
|
|
fadb0a5bf2 | ||
|
|
fa7aa6cedb | ||
|
|
6df98f2fad | ||
|
|
c597017402 | ||
|
|
9cb95f6065 | ||
|
|
477b1535a2 | ||
|
|
1d652cfcbd | ||
|
|
28b604c7c7 | ||
|
|
8c11be07cd | ||
|
|
e8dd2c28ff | ||
|
|
0bdffc4a2d | ||
|
|
94b1fe4a8b | ||
|
|
11ed445319 | ||
|
|
400dfb4e6b | ||
|
|
6b951734ce | ||
|
|
000fcfd1ac | ||
|
|
051e2ed6cd | ||
|
|
aac406a245 | ||
|
|
ef2952b5fd | ||
|
|
ffdf54b097 | ||
|
|
58593d7da6 | ||
|
|
3d13f36ce2 | ||
|
|
8c843ec6d0 | ||
|
|
232c7f5301 | ||
|
|
16cd8caef3 | ||
|
|
43dabee53d | ||
|
|
f016760851 | ||
|
|
99b5166f21 | ||
|
|
4aa29db7aa | ||
|
|
f5b8b18c8e | ||
|
|
6e5566f9c8 | ||
|
|
ca216ae819 | ||
|
|
4713241444 | ||
|
|
4917170a0d | ||
|
|
87775ae37a | ||
|
|
eaa244a2a3 | ||
|
|
db91d66d1a | ||
|
|
4d64481564 | ||
|
|
0a31fc176c | ||
|
|
659a8c967c | ||
|
|
626887a792 | ||
|
|
256b66de41 | ||
|
|
5ee4f37b8d | ||
|
|
3dc122db84 | ||
|
|
99c5a4e2f8 | ||
|
|
f922a92ffa | ||
|
|
a36de8ba1a | ||
|
|
e3d30763da | ||
|
|
c73518d8ec | ||
|
|
ed0d2fed66 | ||
|
|
960bcb6b53 | ||
|
|
6252340804 | ||
|
|
517d67b2e0 | ||
|
|
e95b7ca3a0 | ||
|
|
c771d7c31a | ||
|
|
ce0e8d7497 | ||
|
|
852678e238 | ||
|
|
16e6eec3fb | ||
|
|
afe8552be6 | ||
|
|
cd0e50da24 | ||
|
|
85001c034b | ||
|
|
a56f6576e2 | ||
|
|
d3e5d05026 | ||
|
|
322b619a71 | ||
|
|
dff906ca69 | ||
|
|
515d1d5e63 | ||
|
|
bb6ed22594 | ||
|
|
d655e1d765 | ||
|
|
db70ed006d | ||
|
|
ce1dd5c632 | ||
|
|
9e2a253dda | ||
|
|
95c645865d | ||
|
|
ceb510bbf5 | ||
|
|
2590e3c99b | ||
|
|
f2f9cfaf28 | ||
|
|
62db8c3969 | ||
|
|
ae3db366e5 | ||
|
|
57570c144a | ||
|
|
c3a235242e | ||
|
|
b629eb5657 | ||
|
|
2e674cd0b3 | ||
|
|
3330e9a19a | ||
|
|
c5f6208396 | ||
|
|
c0d93bbcf4 | ||
|
|
db941e7007 | ||
|
|
4761857157 | ||
|
|
3aefe23184 | ||
|
|
6f852814fd | ||
|
|
b15e521b0e | ||
|
|
63c401e6d6 | ||
|
|
e59750e8de | ||
|
|
9c184ddfd0 | ||
|
|
9df6e821d8 | ||
|
|
9551dc5ecd | ||
|
|
d372daff60 | ||
|
|
f742e6e394 | ||
|
|
414b2b0e4c | ||
|
|
603c5692ae | ||
|
|
b35e994d1b | ||
|
|
abe2ab229a | ||
|
|
5ad9939bcf | ||
|
|
ce451128ba | ||
|
|
70470016cc | ||
|
|
2122ea77e1 | ||
|
|
69266cd6c6 | ||
|
|
062d61567e | ||
|
|
d6120fc908 | ||
|
|
91f8e7a07b | ||
|
|
f57d89245c | ||
|
|
c307a71f53 | ||
|
|
1e4e59bb57 | ||
|
|
f62d16d274 | ||
|
|
f175712d4b | ||
|
|
5f942d78e6 | ||
|
|
538c8885ad | ||
|
|
c8158c3d62 | ||
|
|
1f4762060f | ||
|
|
81c3682781 | ||
|
|
2e6e1fdd55 | ||
|
|
1a09cd560b | ||
|
|
8c9d2bc6f6 | ||
|
|
78ad5ca713 | ||
|
|
43c2e71b25 | ||
|
|
5b9f32fade | ||
|
|
76a1a6da34 | ||
|
|
a2b0abc90d | ||
|
|
0fd8e02a88 | ||
|
|
55c4bfb670 | ||
|
|
ea1030f8bf | ||
|
|
6dd285811a | ||
|
|
ee149ed1eb | ||
|
|
c3aa96d423 | ||
|
|
6e59d95da5 | ||
|
|
a396e74a79 | ||
|
|
80bdb39ae3 | ||
|
|
5cb1a9dcc6 | ||
|
|
1cfa81450c | ||
|
|
1f18fed3a2 | ||
|
|
33cb429e15 | ||
|
|
cfdbf02e6b | ||
|
|
f8c631a3f0 | ||
|
|
74911e9f6d | ||
|
|
0f453ae4cf | ||
|
|
febebc8d3d | ||
|
|
166c45f97f | ||
|
|
af58364fef | ||
|
|
eadf83d61b | ||
|
|
3c20231aad | ||
|
|
402bf395d1 | ||
|
|
9a45938fe6 | ||
|
|
d963e4a2c4 | ||
|
|
1063a67ae2 | ||
|
|
602ef883bb | ||
|
|
aad6042d42 | ||
|
|
85d8c1a97e | ||
|
|
547e6542ba | ||
|
|
f74044f9b0 | ||
|
|
42651707f8 | ||
|
|
95c13eaf5a | ||
|
|
c74068ae4d | ||
|
|
ca92dd0299 | ||
|
|
798f791b6b | ||
|
|
331622309f | ||
|
|
4f334525c2 | ||
|
|
82e704ec5b | ||
|
|
67aaa97904 | ||
|
|
4f55248a6c | ||
|
|
61b46f1a3e | ||
|
|
286104a988 | ||
|
|
8ea6ead08a | ||
|
|
bd9cc23681 | ||
|
|
f2d7298cf4 | ||
|
|
da636ca881 | ||
|
|
39bfa30185 | ||
|
|
d7c005a2f1 | ||
|
|
763b69bf5b | ||
|
|
2f2e353ece | ||
|
|
0092b7c0a4 | ||
|
|
9f48109640 | ||
|
|
b976adb8aa | ||
|
|
fe38c81e07 | ||
|
|
fed9bc7072 | ||
|
|
044e252d19 | ||
|
|
6920fb2793 | ||
|
|
3d1171de8d | ||
|
|
6e09754d06 | ||
|
|
32f2de17d4 | ||
|
|
600e8081a8 | ||
|
|
59fd7c3c9a | ||
|
|
7e70fe1126 | ||
|
|
5265c774ae | ||
|
|
d1421d720c | ||
|
|
2bd09d3b30 | ||
|
|
56e54ac820 | ||
|
|
08d85798ed | ||
|
|
38c2b36606 | ||
|
|
01b747287a | ||
|
|
c925e13e5a | ||
|
|
1ced89a869 | ||
|
|
a5e32dc3de | ||
|
|
150174c3bb | ||
|
|
601ee0b40b | ||
|
|
9627c3e7c8 | ||
|
|
d88c67eba3 | ||
|
|
bb38a90dda | ||
|
|
c36743f7ee | ||
|
|
860275f888 | ||
|
|
670228ff63 | ||
|
|
4338e4ef86 | ||
|
|
dbc712c53c | ||
|
|
bb6011ea73 | ||
|
|
1915f34de8 | ||
|
|
675f26fe90 | ||
|
|
491e309911 | ||
|
|
283d27c5b1 | ||
|
|
24d862c1bc | ||
|
|
3708c1ac8c | ||
|
|
df60be423a | ||
|
|
a1e583129f | ||
|
|
a06b28b693 | ||
|
|
198070700c | ||
|
|
3a01aa40d8 | ||
|
|
b628af2258 | ||
|
|
0cb5d0d63e | ||
|
|
526c85e2ca | ||
|
|
8a21c8e618 | ||
|
|
8d3d5747d2 | ||
|
|
f1f1406596 | ||
|
|
9e42be9884 | ||
|
|
75e75b93cf | ||
|
|
0e8ecbc9fc | ||
|
|
a88236b36f | ||
|
|
df06c54bd2 | ||
|
|
f2d88387c9 | ||
|
|
db4c6bbd3b | ||
|
|
c8e7f79f50 | ||
|
|
1157dc7dc8 | ||
|
|
c12833521f | ||
|
|
5d9346999e | ||
|
|
52c0631833 | ||
|
|
e16aefec2c | ||
|
|
053a247cc8 | ||
|
|
1426b7a6dc | ||
|
|
ec66949b35 | ||
|
|
bc9d8d1136 | ||
|
|
542a527d0d | ||
|
|
5e0c392287 | ||
|
|
05ff94941c | ||
|
|
a27d75d610 | ||
|
|
446e842904 | ||
|
|
ba153e2c18 | ||
|
|
3342ea6891 | ||
|
|
8c3d5fd295 | ||
|
|
5fc58fb10a | ||
|
|
4e2ae9cd4e | ||
|
|
4167ca2e5c | ||
|
|
9b3e9dcf02 | ||
|
|
f203fcc92e | ||
|
|
0b20069c20 | ||
|
|
bad7b778b3 | ||
|
|
f89ce93940 | ||
|
|
1ddbc8a26d | ||
|
|
0a3094fc9a | ||
|
|
816bbad28a | ||
|
|
ce4150cd06 | ||
|
|
be19b75031 | ||
|
|
3ddab5966b | ||
|
|
2d5c99f459 | ||
|
|
a5a1bbf5d7 | ||
|
|
c4af4e3297 | ||
|
|
1acfc05e2d | ||
|
|
b40c38f58c | ||
|
|
87c41cb9ac | ||
|
|
0ec715d7c9 | ||
|
|
e6a261a789 | ||
|
|
3bd2a91992 | ||
|
|
c721bc672c | ||
|
|
931b876b44 | ||
|
|
87b91e5023 | ||
|
|
4b1384be83 | ||
|
|
8da6e6a096 | ||
|
|
5181e575b4 | ||
|
|
ca994735be | ||
|
|
718c303086 | ||
|
|
7200c71673 | ||
|
|
14c97799c6 | ||
|
|
a06e8bfaee | ||
|
|
7dad60bbd5 | ||
|
|
a66b4626fb | ||
|
|
330add963d | ||
|
|
da1ccc620b | ||
|
|
c412c01a65 | ||
|
|
74d7fa61d9 | ||
|
|
ef6ea4484e | ||
|
|
ba2d775215 | ||
|
|
f866771854 | ||
|
|
70b8c57d22 | ||
|
|
b04e0d0fd4 | ||
|
|
3f9d5e11d1 | ||
|
|
09fe271b25 | ||
|
|
d5c1a49984 | ||
|
|
e80d3653c9 | ||
|
|
30b0d0a5cc | ||
|
|
9beceb9b02 | ||
|
|
6f13cabfba | ||
|
|
7bd2de9967 | ||
|
|
b0b0973e2d | ||
|
|
3d866e8975 | ||
|
|
63fb8d0392 | ||
|
|
384de0925e | ||
|
|
5b5c569c82 | ||
|
|
6f2371ee74 | ||
|
|
d6e7d90197 | ||
|
|
aa73db0fe6 | ||
|
|
d85088fc3d | ||
|
|
7e21aeedcd | ||
|
|
342460fa17 | ||
|
|
e57211fbd1 | ||
|
|
d31eb4c89c | ||
|
|
6753d260e4 | ||
|
|
a3092204a1 | ||
|
|
10b49af776 | ||
|
|
3497ced9f9 | ||
|
|
7a0f22b0a7 | ||
|
|
4f03272a5f | ||
|
|
7755936a2e | ||
|
|
9f6844ec30 | ||
|
|
c2952aa803 | ||
|
|
8f7383f5c2 | ||
|
|
750641ef19 | ||
|
|
fb48dfc082 | ||
|
|
1de5bce1c1 | ||
|
|
676603239d | ||
|
|
4c87f36a8c | ||
|
|
12b2137a04 | ||
|
|
762e1c9c2b | ||
|
|
cd26ead043 | ||
|
|
6a560cfec4 | ||
|
|
489ba72d5c | ||
|
|
5df9779669 | ||
|
|
e49d2f6b8f | ||
|
|
9550a7a954 | ||
|
|
d9f855b97e | ||
|
|
e275dae6e3 | ||
|
|
88ccc2a3b9 | ||
|
|
84487edc05 | ||
|
|
7177649969 | ||
|
|
18b7b3f125 | ||
|
|
89c7e1a8ee | ||
|
|
774a9b118e | ||
|
|
327841280b | ||
|
|
1e0a686561 | ||
|
|
96883100b4 | ||
|
|
1fcb05ed8c | ||
|
|
8c85516c57 | ||
|
|
6989a3eaad | ||
|
|
57796a2f96 | ||
|
|
59b217f7ea | ||
|
|
fb9a193c44 | ||
|
|
2739f1f3f0 | ||
|
|
0c2cb18578 | ||
|
|
db2c5aae84 | ||
|
|
aa2cec103b | ||
|
|
a532a70ac0 | ||
|
|
ec6cec8854 | ||
|
|
3fb22d27ab | ||
|
|
1cbaab5889 | ||
|
|
fef19b47c2 | ||
|
|
5126613825 | ||
|
|
07097d2fa3 | ||
|
|
8c9fb32ca0 | ||
|
|
68d921e918 | ||
|
|
330b36159d | ||
|
|
046152e798 | ||
|
|
11ca5bb7d5 | ||
|
|
e0838ff8ab | ||
|
|
11a2419c22 | ||
|
|
f3420c0adb | ||
|
|
bd84ff4838 | ||
|
|
87689df062 | ||
|
|
1bfbd57ee4 | ||
|
|
64d7585282 | ||
|
|
0ee03a565f | ||
|
|
1b0e268416 | ||
|
|
0e8d1afcaf | ||
|
|
48a33f08e2 | ||
|
|
f9ca956510 | ||
|
|
65a472c113 | ||
|
|
4b17ea04a7 | ||
|
|
423fdc0a96 | ||
|
|
396b124e84 | ||
|
|
6a27afa6ac | ||
|
|
b9812ba06a | ||
|
|
bc6aded074 | ||
|
|
904401617a | ||
|
|
02089f15c4 | ||
|
|
43a18a2569 | ||
|
|
4c2dc2bf16 | ||
|
|
e6eb2a8476 | ||
|
|
af5ae163f3 | ||
|
|
d00860430f | ||
|
|
af0b4a0fca | ||
|
|
404189f88c | ||
|
|
1a27fad9b9 | ||
|
|
c2cfe481df | ||
|
|
3a56fb6ec6 | ||
|
|
61950decb3 | ||
|
|
1a614ea023 | ||
|
|
a83b6a5e63 | ||
|
|
65d98af24c | ||
|
|
62d35627f3 | ||
|
|
84f1ed1587 | ||
|
|
31b4fb343d | ||
|
|
3c3f5c60da | ||
|
|
18914f2081 | ||
|
|
b50da2d8b7 | ||
|
|
5bdd699c9d | ||
|
|
29e8e6d95c | ||
|
|
049fc91615 | ||
|
|
b7c96f2cbd | ||
|
|
1e6408df13 | ||
|
|
7b90548c1d | ||
|
|
5d330e18ff | ||
|
|
07662ff076 | ||
|
|
9252ae1596 | ||
|
|
0155e9131d | ||
|
|
247cf40ace | ||
|
|
4a6b450c55 | ||
|
|
5b80d57a54 | ||
|
|
8ac4547e73 | ||
|
|
3658975b69 | ||
|
|
abc3545ef9 | ||
|
|
01f8cb698d | ||
|
|
5e4d0f45fc | ||
|
|
efd2f78274 | ||
|
|
690ff955fa | ||
|
|
3fb27bdc55 | ||
|
|
d8306fca6f | ||
|
|
380775540d | ||
|
|
65e3b0dafd | ||
|
|
4ae81d753c | ||
|
|
0f01aac823 | ||
|
|
ce0a96351e | ||
|
|
93dda6f1fd | ||
|
|
5e83db959e | ||
|
|
74436eb03e | ||
|
|
993178fc49 | ||
|
|
1c217cf446 | ||
|
|
0bf2be1f9d | ||
|
|
548589be4d | ||
|
|
697a1b1ed1 | ||
|
|
d893c7eb33 | ||
|
|
8957d24752 | ||
|
|
677e730235 | ||
|
|
4227d973b9 | ||
|
|
06c0af50c3 | ||
|
|
4d3a48d1c1 | ||
|
|
f6b66f4cad | ||
|
|
a56f9ab4e6 | ||
|
|
ca913e5077 | ||
|
|
b25ebe12c5 | ||
|
|
984980b170 | ||
|
|
be45005dbb | ||
|
|
b8c9f04989 | ||
|
|
bf2d41eb14 | ||
|
|
158f9afb37 | ||
|
|
f884e31d21 | ||
|
|
d3a5ff9d68 | ||
|
|
7185780d4e | ||
|
|
f995b2822f | ||
|
|
d7490ac738 | ||
|
|
383d0e17f2 | ||
|
|
7c1a3ab36e | ||
|
|
edc8d17031 | ||
|
|
f3f861234d | ||
|
|
93278c00b7 | ||
|
|
5bbe93d49f | ||
|
|
21cd8d31d7 | ||
|
|
d649b4df28 | ||
|
|
2bb9550343 | ||
|
|
ef0feff4a5 | ||
|
|
dfa43b4856 | ||
|
|
a24a1ca6d7 | ||
|
|
2d4b35fbc9 | ||
|
|
57e2910477 | ||
|
|
ffbaa7e4dc | ||
|
|
df42036100 | ||
|
|
ca9491d343 | ||
|
|
96ae569eaf | ||
|
|
fb295d53f1 | ||
|
|
95d07974f4 | ||
|
|
39d78064da | ||
|
|
a2bcbb90ed | ||
|
|
c31b37f570 | ||
|
|
2a1341b910 | ||
|
|
354e341d69 | ||
|
|
13946b2b76 | ||
|
|
29aa52df6a | ||
|
|
c3267a27d3 | ||
|
|
3543e6dd32 | ||
|
|
5412ba617d | ||
|
|
1f81a2cb1b | ||
|
|
5da58d42f6 | ||
|
|
299b6037c9 | ||
|
|
1ed8b9dd14 | ||
|
|
cf4912cb3d | ||
|
|
e6ec87f910 | ||
|
|
f72fb974a9 | ||
|
|
bdb25315b6 | ||
|
|
60f0739c3e | ||
|
|
0faab9277f | ||
|
|
51fce12cd7 | ||
|
|
d79290df75 | ||
|
|
0bf65bcad5 | ||
|
|
44dbf19e89 | ||
|
|
469a76f1f6 | ||
|
|
f851c272fa | ||
|
|
027a9fec61 | ||
|
|
09fde2f839 | ||
|
|
8a14e4261d | ||
|
|
6c9f1de265 | ||
|
|
3ad0179b62 | ||
|
|
81f33da499 | ||
|
|
80d70e64f5 | ||
|
|
eec4845cd0 | ||
|
|
b99a4ade1a | ||
|
|
84e25e8fd2 | ||
|
|
39e14eb95c | ||
|
|
f277d08244 | ||
|
|
d7c479fa6d | ||
|
|
44e5dc7d97 | ||
|
|
fdd54057a8 | ||
|
|
d43485141f | ||
|
|
2350561903 | ||
|
|
5674badccd | ||
|
|
a793f4414d | ||
|
|
e99957f99f | ||
|
|
ad5bbc463b | ||
|
|
81993cf2a3 | ||
|
|
5d40742ee6 | ||
|
|
1ce050d911 | ||
|
|
8e7393fc26 | ||
|
|
ad45205ddf | ||
|
|
409e9208ee | ||
|
|
d8811b499d | ||
|
|
dd1f9494f1 | ||
|
|
20f4538db4 | ||
|
|
d08c8e6edc | ||
|
|
f1667dbbe6 | ||
|
|
2bab7e2693 | ||
|
|
824497b97a | ||
|
|
0b7bece8e3 | ||
|
|
6ddf1a5786 | ||
|
|
b9827dfe02 | ||
|
|
64f30831ac | ||
|
|
bf5722cd25 | ||
|
|
ae074153c8 | ||
|
|
63d46dbdfb | ||
|
|
bdf1b23198 | ||
|
|
6f1c261f6b | ||
|
|
3233d5485f | ||
|
|
aa06400a50 | ||
|
|
30724bd7c4 | ||
|
|
0d3b389538 | ||
|
|
9f7dbe16fd | ||
|
|
432024123a | ||
|
|
261762448e | ||
|
|
7ce4175876 | ||
|
|
a57739c462 | ||
|
|
03bdbfa705 | ||
|
|
92246ce3a8 | ||
|
|
cdf74c2e41 | ||
|
|
4a72ea6666 | ||
|
|
f76d9b7908 | ||
|
|
dcfdf3a5d7 | ||
|
|
4873f61d6c | ||
|
|
1538107ae4 | ||
|
|
9b93dc5137 | ||
|
|
5ec721b978 | ||
|
|
24568c0e2f | ||
|
|
92a89ca258 | ||
|
|
ba71c53bc6 | ||
|
|
b3cfeb573a | ||
|
|
9083e99d2a | ||
|
|
70ca247c88 | ||
|
|
14fc0c735b | ||
|
|
70b3c8080e | ||
|
|
2c483c460a | ||
|
|
79405cf1d3 | ||
|
|
5c755fdd1c | ||
|
|
89285f1408 | ||
|
|
17c0bb2069 | ||
|
|
192736f6d7 | ||
|
|
ae928b9aff | ||
|
|
4eee8ce770 | ||
|
|
723eb6597a | ||
|
|
3dcfdba74b | ||
|
|
5428053663 | ||
|
|
d0b41d0b07 | ||
|
|
a82d861d2c | ||
|
|
1e184b781b | ||
|
|
54b684fdb8 | ||
|
|
c1ddb89990 | ||
|
|
2f5fa4df75 | ||
|
|
20735083b3 | ||
|
|
7ac7cb129f | ||
|
|
f8b2f738bb | ||
|
|
11b9e546a9 | ||
|
|
7e4721e4c7 | ||
|
|
3a3fd38e3a | ||
|
|
63a8611579 | ||
|
|
38a1b79174 | ||
|
|
0a679e503e | ||
|
|
e7c529f2c3 | ||
|
|
95cbcf30d7 | ||
|
|
dfc70021e3 | ||
|
|
9daecca0ad | ||
|
|
c9d8a4dc1d | ||
|
|
5fada6a497 | ||
|
|
ac9c33fb3b | ||
|
|
641b1c2e1b | ||
|
|
f031707563 | ||
|
|
7f0518f693 | ||
|
|
634d2f02b5 | ||
|
|
d7aee292d3 | ||
|
|
1987517836 | ||
|
|
203d9d651f | ||
|
|
8af5788fc1 | ||
|
|
3de81877c6 | ||
|
|
2665b34962 | ||
|
|
2ffef2be8f | ||
|
|
c2e5610455 | ||
|
|
234bb64250 | ||
|
|
d43a56614c | ||
|
|
9f10e7e356 | ||
|
|
dc6075aa3f | ||
|
|
972d6917ac | ||
|
|
ec3ba87f3a | ||
|
|
da034045cc | ||
|
|
65f001b4b7 | ||
|
|
d81473487f | ||
|
|
06a8d5a4fa | ||
|
|
3653a86ad3 | ||
|
|
c8d913fba7 | ||
|
|
b70acd0079 | ||
|
|
f167648115 | ||
|
|
b457c66bf9 | ||
|
|
ca0bd3ed32 | ||
|
|
7dacc7c268 | ||
|
|
0db2e6b62c | ||
|
|
e412bdbdbe | ||
|
|
f032bcc5f2 | ||
|
|
9ab9ac0e2e | ||
|
|
fd3adf4d11 | ||
|
|
c42911bd8d | ||
|
|
828087ee8c | ||
|
|
efcda1d37d | ||
|
|
656400b418 | ||
|
|
ca7bd49964 | ||
|
|
3527137264 | ||
|
|
e045a36559 | ||
|
|
ee8fc701a6 | ||
|
|
777fdeb462 | ||
|
|
1078b774ae | ||
|
|
62a363debc | ||
|
|
7839b931f1 | ||
|
|
cbf8c4bdb2 | ||
|
|
321cd9f2e0 | ||
|
|
09a60774d7 | ||
|
|
1ca988b177 | ||
|
|
07fd8cf6cd | ||
|
|
e7fb56447a | ||
|
|
de3e83f0a2 | ||
|
|
6c78f7b769 | ||
|
|
2c459fefce | ||
|
|
a1eb39872b | ||
|
|
724b8cc6a5 | ||
|
|
2bfd18e6cd | ||
|
|
20658f3b4a | ||
|
|
c945698eb4 | ||
|
|
5f89bd75a4 | ||
|
|
09c9b47265 | ||
|
|
ea2b653b9b | ||
|
|
9c3660e2f6 | ||
|
|
4bcacf858b | ||
|
|
7faa3359f0 | ||
|
|
71f1814477 | ||
|
|
a3913c5ca4 | ||
|
|
ae1cc65b23 | ||
|
|
9a16bf65bd | ||
|
|
c3d3dc9d92 | ||
|
|
e54eb21b71 | ||
|
|
0140f9fe56 | ||
|
|
03243df16a | ||
|
|
28dc8443a8 | ||
|
|
ec6832687b | ||
|
|
9065a90ac0 | ||
|
|
94b26e1e66 | ||
|
|
a2fc2e776a | ||
|
|
79b40179b4 | ||
|
|
60c968222f | ||
|
|
e99dc2193f | ||
|
|
cf1838f76e | ||
|
|
0db5016666 | ||
|
|
c4b37ba462 | ||
|
|
c3b908dcfc | ||
|
|
23f93044c1 | ||
|
|
32dcc28414 | ||
|
|
ddae3eaf84 | ||
|
|
a9ae17036d | ||
|
|
08e925758e | ||
|
|
213c8a6eec | ||
|
|
ca4ad836a3 | ||
|
|
56361fa2fc | ||
|
|
fedce4cd74 | ||
|
|
cac48fc4bf | ||
|
|
1cad844d2d | ||
|
|
2d5e09f930 | ||
|
|
fbda34935d | ||
|
|
c5ca7f236f | ||
|
|
9dc949b62c | ||
|
|
40394b94d7 | ||
|
|
bae446973f | ||
|
|
2805520d1b | ||
|
|
fb7ca18820 | ||
|
|
1b00d5657f | ||
|
|
cd9f35e78a | ||
|
|
f9cedab964 | ||
|
|
9ec516e5a4 | ||
|
|
550b6d90a4 | ||
|
|
5cb92b6e21 | ||
|
|
8a7b221412 | ||
|
|
d092e79ebc | ||
|
|
2ddb88a34d | ||
|
|
71761c9039 | ||
|
|
16555b93bb | ||
|
|
bd5e834b42 | ||
|
|
2eb4f093be | ||
|
|
d4bf587103 | ||
|
|
ae7bd8b644 | ||
|
|
f89cede020 | ||
|
|
59facf6f00 | ||
|
|
01d93733ae | ||
|
|
4c434129a6 | ||
|
|
b40499b4c1 | ||
|
|
66333aedb7 | ||
|
|
47071c58aa | ||
|
|
79d99688b4 | ||
|
|
edcb0631aa | ||
|
|
bc361e6469 | ||
|
|
c95ef1a5c0 | ||
|
|
0c0891f64f | ||
|
|
23828f53bc | ||
|
|
f909e129ab | ||
|
|
7d4bcc2e8b | ||
|
|
2eb4d87621 | ||
|
|
435888c1a3 | ||
|
|
e69fabcd71 | ||
|
|
1a283301cf | ||
|
|
031df70cf8 | ||
|
|
3ad36db7dd | ||
|
|
e16ea1ae05 | ||
|
|
941135a0a6 | ||
|
|
29776ecea2 | ||
|
|
d2edef5c5a | ||
|
|
da9349ea62 | ||
|
|
de0d2afc15 | ||
|
|
d8c94c2003 | ||
|
|
0e71bfe222 | ||
|
|
0ae402e624 | ||
|
|
b96dc11ddd | ||
|
|
37b539eaa5 | ||
|
|
0741708086 | ||
|
|
a30cfd8fec | ||
|
|
633cd11c5b | ||
|
|
3101c6540a | ||
|
|
d2d6be73b8 | ||
|
|
a46e2c1e6d | ||
|
|
2b0404fefc | ||
|
|
7ef9462286 | ||
|
|
c6e7a7eaee | ||
|
|
999e142370 | ||
|
|
a7ad117a83 | ||
|
|
1ba44fc117 | ||
|
|
ca5610ebf1 | ||
|
|
e5c70a1304 | ||
|
|
7dd2308534 | ||
|
|
62eee07b6e | ||
|
|
f6d9406063 | ||
|
|
34125177e8 | ||
|
|
d977b5d662 | ||
|
|
e36677b757 | ||
|
|
4d54755057 | ||
|
|
91917c98e4 | ||
|
|
2f687de477 | ||
|
|
5446062b95 | ||
|
|
c9e170dfcc | ||
|
|
e3a19469eb | ||
|
|
45f8e43be4 | ||
|
|
7ef0b05ce6 | ||
|
|
c5a0ec4e93 | ||
|
|
1c17768dc5 | ||
|
|
86e1dd4673 | ||
|
|
0ee41c3341 | ||
|
|
e1c2835173 | ||
|
|
5c6d3753ef | ||
|
|
6e881bcef2 | ||
|
|
4f9a933108 | ||
|
|
9f8585914c | ||
|
|
3ba27b9752 | ||
|
|
abae5de4d8 | ||
|
|
6952c5a3f5 | ||
|
|
0184d2c292 | ||
|
|
7a40561aaa | ||
|
|
79e6c9590a | ||
|
|
12a963cc40 | ||
|
|
f89975fd0e | ||
|
|
b4dffe5946 | ||
|
|
539b69d507 | ||
|
|
9927363f39 | ||
|
|
1a4f59cd70 | ||
|
|
25727a24a5 | ||
|
|
2fd2dc964b | ||
|
|
935b032f15 | ||
|
|
2bb58843ab | ||
|
|
00512579f3 | ||
|
|
6f09796142 | ||
|
|
697a74f37e | ||
|
|
d16b6c3838 | ||
|
|
e4461f2e61 | ||
|
|
baf1b8b02d | ||
|
|
3ce1373ae0 | ||
|
|
4002531b92 | ||
|
|
004d0f074d | ||
|
|
e87887c328 | ||
|
|
2de2c8e207 | ||
|
|
c76f19f19a | ||
|
|
a050e8c8f5 | ||
|
|
ae1fad5de7 | ||
|
|
68ca8951a8 | ||
|
|
1e4718eae1 | ||
|
|
680cf25f37 | ||
|
|
7ec6df495f | ||
|
|
aeda31fda7 | ||
|
|
5248aa3065 | ||
|
|
67767c5853 | ||
|
|
6de1aec683 | ||
|
|
221d3cdf6a | ||
|
|
1ff12c5520 | ||
|
|
41376ec2cd | ||
|
|
bf335ecaf3 | ||
|
|
424bc73f58 | ||
|
|
59e6989cbc | ||
|
|
0e6b27c9f4 | ||
|
|
0e157e4e8b | ||
|
|
805074a0f9 | ||
|
|
5216c5b232 | ||
|
|
8633162f0c | ||
|
|
c392a77b46 | ||
|
|
08c2c9bc22 | ||
|
|
f64bd590a8 | ||
|
|
131ffcf582 | ||
|
|
b17a0aef17 | ||
|
|
8a21783fa5 | ||
|
|
53152e2ef5 | ||
|
|
ca6ba92d82 | ||
|
|
04516b787a | ||
|
|
6e124a4d72 | ||
|
|
6da65c7ddc | ||
|
|
9eb332f032 | ||
|
|
30ddee65a4 | ||
|
|
63dc8d7fc4 | ||
|
|
a1a287bac7 | ||
|
|
e9b786d5e8 | ||
|
|
ad9fb411f6 | ||
|
|
1ff982983e | ||
|
|
8c6c43d762 | ||
|
|
6baf197842 | ||
|
|
42e5a50e4f | ||
|
|
b713c9a491 | ||
|
|
64ade742d9 | ||
|
|
1870c3c876 | ||
|
|
23b272aafd | ||
|
|
057db41758 | ||
|
|
839c5a8e41 | ||
|
|
36b8b6bf6c | ||
|
|
40d74fa779 | ||
|
|
249bdeb642 | ||
|
|
b4ee80d1ea | ||
|
|
96bf9d0769 | ||
|
|
7fc9c83986 | ||
|
|
5502f1cc63 | ||
|
|
b55801323c | ||
|
|
818374c8cc | ||
|
|
e80191d4cd | ||
|
|
c2a796b6ea | ||
|
|
00694f0dfd | ||
|
|
134f4c5b52 | ||
|
|
0840fc42f9 | ||
|
|
2650a647e9 | ||
|
|
3311269162 | ||
|
|
b2172d39f6 | ||
|
|
f4d39bd3c8 | ||
|
|
1cf659033b | ||
|
|
3dc5527690 | ||
|
|
81b02d04b5 | ||
|
|
95f6f9e10a | ||
|
|
9554f53519 | ||
|
|
5d7081a224 | ||
|
|
9cbdf3f31f | ||
|
|
c8bc1b560b | ||
|
|
40ae6b396f | ||
|
|
9c117ffa05 | ||
|
|
9e95f189ed | ||
|
|
221b31bcc6 | ||
|
|
8879776d64 | ||
|
|
5edd13c6bb | ||
|
|
7ca289edd0 | ||
|
|
bf434818d7 | ||
|
|
03aeb88832 | ||
|
|
bb5b33a0d3 | ||
|
|
53931017b9 | ||
|
|
e9ca17cec1 | ||
|
|
f70956964b | ||
|
|
4547a9d9d3 | ||
|
|
71accb6b0a | ||
|
|
2a95500b65 | ||
|
|
2ddad66ce7 | ||
|
|
108be24aed | ||
|
|
71efb05658 | ||
|
|
a9a36894cb | ||
|
|
bc9778e02f | ||
|
|
a83d2efe84 | ||
|
|
d3856caf81 | ||
|
|
e1f9b1c47d | ||
|
|
497c953d0e | ||
|
|
bec76bd057 | ||
|
|
54f4762e1a | ||
|
|
8bf5c18425 | ||
|
|
c36bb17475 | ||
|
|
2291fcdf11 | ||
|
|
4070c46d15 | ||
|
|
a749db8d0f | ||
|
|
10ba98c4f5 | ||
|
|
108a3efe0b | ||
|
|
ccd826f63a | ||
|
|
5e5f0aa955 | ||
|
|
f9a4c53e3f | ||
|
|
60b576568e | ||
|
|
d0e1b73205 | ||
|
|
ef2448e17e | ||
|
|
99a5cf1ad4 | ||
|
|
bc3113ae16 | ||
|
|
fb475da008 | ||
|
|
d5fc3ad646 | ||
|
|
8b7da6e318 | ||
|
|
ed208c4bcc | ||
|
|
6ab65519a0 | ||
|
|
4549bc89ec | ||
|
|
a0430f91bd | ||
|
|
624bb1db8d | ||
|
|
9f522bbe6c | ||
|
|
931da3b4f7 | ||
|
|
5a25fd54a4 | ||
|
|
9f0f4c50a4 | ||
|
|
0bf3d31578 | ||
|
|
8ca293c3e4 | ||
|
|
ba0c877ffc | ||
|
|
b8e00c2dc9 | ||
|
|
2dd48898a8 | ||
|
|
66fc807655 | ||
|
|
653eb2909b | ||
|
|
72520a2dd9 | ||
|
|
a7d4666a70 | ||
|
|
13476d5003 | ||
|
|
879cdedec3 | ||
|
|
05bd2a1f9e | ||
|
|
c49d1547c4 | ||
|
|
ad35363c2e | ||
|
|
b3f70140e5 | ||
|
|
2f21dc50b4 | ||
|
|
cbd8c2483b | ||
|
|
03475bfb15 | ||
|
|
bb9411e7dc | ||
|
|
bce4e2d022 | ||
|
|
7cfc14fef7 | ||
|
|
f220cf3173 | ||
|
|
725359b1aa | ||
|
|
937d6cb1ef | ||
|
|
118a5edebc | ||
|
|
1b4333e8d9 | ||
|
|
d66a0b50e9 | ||
|
|
1d56b9a1bb | ||
|
|
96535ee4df | ||
|
|
b55f314d7e | ||
|
|
480862d714 | ||
|
|
990a3af2a7 | ||
|
|
1f5a23143a | ||
|
|
fcfb9e9758 | ||
|
|
9beee689ce | ||
|
|
2c388c3833 | ||
|
|
1a75066616 | ||
|
|
3dfb0bcae9 | ||
|
|
9ac0b77e92 | ||
|
|
6421a32520 | ||
|
|
fdcae52740 | ||
|
|
a8752844ef | ||
|
|
e04ce5028e | ||
|
|
f2c4d80ac0 | ||
|
|
d8a6226805 | ||
|
|
fedf60a32c | ||
|
|
b3548fefc1 | ||
|
|
febd64c527 | ||
|
|
d67a5c5070 | ||
|
|
aefe7ddd8f | ||
|
|
254dea7558 | ||
|
|
b1550f7922 | ||
|
|
2d07c3e45d | ||
|
|
e5f3406cb5 | ||
|
|
185ddf1eaf | ||
|
|
2734335869 | ||
|
|
0132c4e36e | ||
|
|
7dee47183d | ||
|
|
9c4988c297 | ||
|
|
3bfbc70587 | ||
|
|
34858fce1c | ||
|
|
b47dab0ee9 | ||
|
|
6eeb033b96 | ||
|
|
0679cb8e00 | ||
|
|
3abc9ee387 | ||
|
|
2e9211cf41 | ||
|
|
40377796ed | ||
|
|
fedad7f31a | ||
|
|
d2a34e0107 | ||
|
|
769c822568 | ||
|
|
c452a621fe | ||
|
|
231ab95ef6 | ||
|
|
7c01b59ffb | ||
|
|
e79668ddf4 | ||
|
|
dc6b6fc353 | ||
|
|
34ea58cf38 | ||
|
|
199168c318 | ||
|
|
063d4bbd7d | ||
|
|
29fd9b9d64 | ||
|
|
c301baafb5 | ||
|
|
4282672201 | ||
|
|
ae705dd865 | ||
|
|
f0fa2ce171 | ||
|
|
d6a9a9927c | ||
|
|
40b4636858 | ||
|
|
97fe499b63 | ||
|
|
e0915cffda | ||
|
|
7602de85c3 | ||
|
|
0787817eb8 | ||
|
|
e030648957 | ||
|
|
b815935fd7 | ||
|
|
a5000ba311 | ||
|
|
5e2bb874c8 | ||
|
|
fcb5a7f645 | ||
|
|
b8c6520abb | ||
|
|
1d99c3d3f7 | ||
|
|
5e112b395d | ||
|
|
d1a8e7813a | ||
|
|
a0582fec12 | ||
|
|
2cd3a7b3f0 | ||
|
|
47448b11cd | ||
|
|
e63f043841 | ||
|
|
33dd0c83e3 | ||
|
|
32dad136f8 | ||
|
|
073ed52538 | ||
|
|
eef828cf3e | ||
|
|
d0b5930a3a | ||
|
|
c66ad9ccc8 | ||
|
|
9959a15c8e | ||
|
|
f0e4b4dc84 | ||
|
|
f62f808368 | ||
|
|
530a521679 | ||
|
|
50782dfb83 | ||
|
|
27a142d5c5 | ||
|
|
6d00b2e63d | ||
|
|
7be1415a3a | ||
|
|
0a30b12f7d | ||
|
|
3058cbfbb2 | ||
|
|
ae780c977b | ||
|
|
e146a67f4b | ||
|
|
162d86983a | ||
|
|
8534366a31 | ||
|
|
d1c6617dc9 | ||
|
|
6f994709b9 | ||
|
|
55d833a9c8 | ||
|
|
8ba4745097 | ||
|
|
940a0c8b10 | ||
|
|
8928b24e23 | ||
|
|
ae9a9191f3 | ||
|
|
cb553bd016 | ||
|
|
a75c61d71e | ||
|
|
c1dc16a89d | ||
|
|
66436ce4a2 | ||
|
|
62b1ff4ba1 | ||
|
|
304d136437 | ||
|
|
1b4268b9b0 | ||
|
|
a7968e6525 | ||
|
|
e59cc3d404 | ||
|
|
3a2d126877 | ||
|
|
ee3d6fcfee | ||
|
|
09d929bd56 | ||
|
|
bd55ae15f2 | ||
|
|
2ca80118bf | ||
|
|
04eb20ac35 | ||
|
|
f299391aa1 | ||
|
|
c334fc9d22 | ||
|
|
8520088376 | ||
|
|
9ada8518dc | ||
|
|
f0c09b374c | ||
|
|
c5f33baf27 | ||
|
|
2efcdd92e0 | ||
|
|
38fda98b6d | ||
|
|
f9fd195c24 | ||
|
|
01e82090b2 | ||
|
|
39602ede37 | ||
|
|
98a311ae40 | ||
|
|
5c398b3e8f | ||
|
|
83e585ee9b | ||
|
|
e386499bfa | ||
|
|
4552630bf8 | ||
|
|
2d8065a780 | ||
|
|
b94da93c74 | ||
|
|
695045f197 | ||
|
|
376733bd08 | ||
|
|
4c7c5137c5 | ||
|
|
930b9820f2 | ||
|
|
b2fa63f2c8 | ||
|
|
1390e1db39 | ||
|
|
e7768ae954 | ||
|
|
38d977e546 | ||
|
|
3e38a24f0a | ||
|
|
481ecee9e8 |
158
.debianinstall/README.md
Normal file
158
.debianinstall/README.md
Normal file
@@ -0,0 +1,158 @@
|
||||
|
||||
# How to use
|
||||
|
||||
## Disclaimers
|
||||
|
||||
- **This script does work with a fresh install of Debian 12 only**.
|
||||
- Do not use if you have already installed and configured a webserver or sql server that was not installed by this script.
|
||||
|
||||
### Keep it Simple and Stupid
|
||||
|
||||
The script keeps everything as simple as possible (KISS):
|
||||
|
||||
- Apache as webserver (there is no choice to use another webserver like nginx)
|
||||
- default PHP version of Debian
|
||||
- one single Hubzilla intance only
|
||||
- re-running the script does no harm
|
||||
|
||||
### When to use other Scripts
|
||||
|
||||
Use the scripts under [homeinstall](https://framagit.org/hubzilla/core/-/tree/master/.homeinstall)
|
||||
if you look for more choices. The main differences are:
|
||||
|
||||
- Apache or nginx as webserver
|
||||
- install multiple instances (domains) that run side by side on the server
|
||||
- adds apache vhosts (instead of using the standard doc root /var/www/html)
|
||||
- install PHP from https://packages.sury.org/php/ (instead of using the Debian repository)
|
||||
- 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)
|
||||
|
||||
## Preconditions
|
||||
|
||||
Hardware
|
||||
|
||||
+ internet connection and router at home
|
||||
+ computer connected to your router (a Raspberry 3 will do for very small Hubs)
|
||||
|
||||
Software
|
||||
|
||||
+ fresh installation of Debian 12 (bookworm)
|
||||
+ 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.
|
||||
|
||||
## How to run the script
|
||||
|
||||
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
|
||||
+ Log on to your fresh Debian
|
||||
- apt-get install git
|
||||
- mkdir -p /var/www
|
||||
- cd /var/www
|
||||
- git clone https://framagit.org/hubzilla/core.git html
|
||||
- cd html/.debianinstall
|
||||
- cp config.txt.template config.txt
|
||||
- nano config.txt
|
||||
- read the comments carefully
|
||||
- enter your values: db pass, domain
|
||||
- (optionally) Enter your values for dyn DNS
|
||||
- ./debian-setup.sh as root
|
||||
- ... wait, wait, wait until the script is finished
|
||||
+ Open your domain with a browser and step throught the initial configuration of your hubzilla instance.
|
||||
- default database name = hubzilla
|
||||
- default dababase user = hubzilla
|
||||
|
||||
## Optional - Switch verification of email on/off
|
||||
|
||||
Do this just before you register the first user without email verification.
|
||||
|
||||
In a terminal
|
||||
|
||||
su -
|
||||
cd /var/www/html
|
||||
|
||||
Check the current setting
|
||||
|
||||
util/config system verify_email
|
||||
|
||||
Switch the verification off
|
||||
|
||||
util/config system verify_email 0
|
||||
|
||||
## What the script will do for you...
|
||||
|
||||
+ install everything required by your hubzilla instance, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||
+ create a database
|
||||
+ run certbot to have everything for a secure connection (httpS)
|
||||
+ create a script for daily maintenance
|
||||
- renew certfificate (letsencrypt)
|
||||
- update of your hubzilla instance for core and addons (git)
|
||||
- update of Debian
|
||||
- restart
|
||||
+ create cron jobs for
|
||||
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
|
||||
- Master.php for your hubzilla instance every 10 minutes
|
||||
- daily maintenance script every day at 05:30
|
||||
|
||||
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)
|
||||
- for tesing purposes: under localhost inside a virtual machine, [KVM](https://wiki.debian.org/KVM)
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
- freedns.afraid.org
|
||||
|
||||
# Step-by-Step - some Details
|
||||
|
||||
## Preparations
|
||||
|
||||
## Configure your Router
|
||||
|
||||
Your webserver has to be visible in the internet.
|
||||
|
||||
Open the ports 80 and 443 on your router for your Debian. Make sure your web server is marked as "exposed host".
|
||||
|
||||
## Preparations Dynamic IP Address
|
||||
|
||||
Follow the instructions in .debianinstall/config.txt.
|
||||
|
||||
In short...
|
||||
|
||||
Your Hubzilla server must be reachable by a domain that you can type in your browser
|
||||
|
||||
cooldomain.org
|
||||
|
||||
You can use subdomains as well
|
||||
|
||||
my.cooldomain.org
|
||||
|
||||
There are two ways to get a domain...
|
||||
|
||||
### Method 1: Buy a Domain
|
||||
|
||||
...for example buy at selfHOST.de
|
||||
|
||||
The cost is 1,50 € per month (2019).
|
||||
|
||||
### Method 2: Register a free subdomain
|
||||
|
||||
...for example register at freedns.afraid.org
|
||||
|
||||
## Note on Rasperry
|
||||
|
||||
It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
sudo raspi-config
|
||||
|
||||
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.
|
||||
111
.debianinstall/config.txt.template
Normal file
111
.debianinstall/config.txt.template
Normal file
@@ -0,0 +1,111 @@
|
||||
|
||||
###############################################
|
||||
### MANDATORY - database password #############
|
||||
#
|
||||
# Please give your database password
|
||||
# It is better to not use blanks inside the password.
|
||||
# Example: db_pass=pass_word_with_no_blanks_in_it
|
||||
db_pass=
|
||||
|
||||
###############################################
|
||||
### MANDATORY - let's encrypt #################
|
||||
#
|
||||
# Zot requires encrypted communication via secure HTTP (HTTPS).
|
||||
# This script automates installation of an SSL certificate from
|
||||
# Let's Encrypt (https://letsencrypt.org)
|
||||
#
|
||||
# Please give the domain name of your hub/instance
|
||||
#
|
||||
# Example: my.cooldomain.org
|
||||
# Example: cooldomain.org
|
||||
#
|
||||
# You might use "localhost" for a LOCAL TEST installation.
|
||||
# This is usefull if you want to debug the server inside a VM.
|
||||
#
|
||||
# Example: localhost
|
||||
#
|
||||
# Email is optional if you use "localhost".
|
||||
#
|
||||
#
|
||||
le_domain=
|
||||
le_email=
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - selfHOST - dynamic IP address ##
|
||||
#
|
||||
# 1. Register a domain at selfhost.de
|
||||
# - choose offer "DOMAIN dynamisch" 1,50€/mon at 04/2019
|
||||
# 2. Get your configuration for dynamic IP update
|
||||
# - Log in at selfhost.de
|
||||
# - go to "DynDNS Accounte"
|
||||
# - klick "Details" of your (freshly) registered domain
|
||||
# - You will find the configuration there
|
||||
# - Benutzername (user name) > use this for "selfhost_user="
|
||||
# - Passwort (pass word) > use this for "selfhost_pass="
|
||||
#
|
||||
#
|
||||
selfhost_user=
|
||||
selfhost_pass=
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - FreeDNS - dynamic IP address ###
|
||||
#
|
||||
# Please give the alpha-numeric-key of freedns
|
||||
#
|
||||
# Get a free subdomain from freedns and use it for your dynamic ip address
|
||||
# Documentation under http://www.techjawab.com/2013/06/setup-dynamic-dns-dyndns-for-free-on.html
|
||||
#
|
||||
# - Register for a Free domain at http://freedns.afraid.org/signup/
|
||||
# - WATCH THIS: Make sure you choose a domain with as less subdomains as
|
||||
# possible. Why? Let's encrpyt issues a limited count of certificates each
|
||||
# day. Possible other users of this domain will try to issue a certificate
|
||||
# at the same day.
|
||||
# - Logon to FreeDNS (where you just registered)
|
||||
# - Goto http://freedns.afraid.org/dynamic/
|
||||
# - Right click on "Direct Link" and copy the URL and paste it somewhere.
|
||||
# - You should notice a large and unique alpha-numeric key in the URL
|
||||
#
|
||||
# http://freedns.afraid.org/dynamic/update.php?alpha-numeric-key
|
||||
#
|
||||
# Provided your url from freedns is
|
||||
#
|
||||
# http://freedns.afraid.org/dynamic/update.php?U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5
|
||||
#
|
||||
# Then you have to provide
|
||||
#
|
||||
# freedns_key=U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5
|
||||
#
|
||||
#
|
||||
freedns_key=
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - do not mess with things below ##
|
||||
# (...if you are not certain)
|
||||
#
|
||||
# Usually you are done here
|
||||
# Everything below is OPTIONAL
|
||||
#
|
||||
###############################################
|
||||
#
|
||||
# Database for your hub/instance
|
||||
# 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
|
||||
#
|
||||
#
|
||||
# Password for package mysql-server
|
||||
# Example: mysqlpass=aberhallo
|
||||
# Example: mysqlpass="aber hallo has blanks in it"
|
||||
#
|
||||
mysqlpass=$db_pass
|
||||
|
||||
# Password for package phpmyadmin
|
||||
# Example: phpmyadminpass=aberhallo
|
||||
# Example: phpmyadminpass="aber hallo has blanks in it"
|
||||
phpmyadminpass=$db_pass
|
||||
|
||||
527
.debianinstall/debian-setup.sh
Normal file
527
.debianinstall/debian-setup.sh
Normal file
@@ -0,0 +1,527 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# How to use
|
||||
# ----------
|
||||
#
|
||||
# This file automates the installation of hubzilla: https://framagit.org/hubzilla/core
|
||||
# under Debian Linux "bookworm"
|
||||
#
|
||||
# 1) Copy the file "config.txt.template" to "config.txt"
|
||||
# Follow the instuctions there
|
||||
#
|
||||
# 2) Switch to user "root" by typing "su -"
|
||||
#
|
||||
# 3) Run with "./debian-setup.sh"
|
||||
# If this fails check if you can execute the script.
|
||||
# - To make it executable type "chmod +x debian-setup.sh"
|
||||
# - or run "bash debian-setup.sh"
|
||||
#
|
||||
#
|
||||
# What does this script do basically?
|
||||
# -----------------------------------
|
||||
#
|
||||
# This file automates the installation of a Hubzilla instance under Debian Linux
|
||||
# - install
|
||||
# * apache webserver,
|
||||
# * php,
|
||||
# * mariadb,
|
||||
# * adminer,
|
||||
# * addons
|
||||
# - configure cron
|
||||
# * "Master.php" for regular background processes of your hubzilla instance
|
||||
# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date
|
||||
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
|
||||
# - run letsencrypt to create, register and use a certifacte for https
|
||||
#
|
||||
#
|
||||
# Credits
|
||||
# -------
|
||||
#
|
||||
# The script is derived from the easyinstall script of the Streams repository, which is based on
|
||||
# - Tom Wiedenhöfts (OJ Random) script homeinstall (for Hubzilla, ZAP,...) that was based on
|
||||
# - Thomas Willinghams script "debian-setup.sh" which he used to install the red#matrix.
|
||||
|
||||
function check_sanity {
|
||||
# Do some sanity checking.
|
||||
print_info "Sanity check..."
|
||||
if [ $(/usr/bin/id -u) != "0" ]
|
||||
then
|
||||
die 'Must be run by root user'
|
||||
fi
|
||||
|
||||
if [ -f /etc/lsb-release ]
|
||||
then
|
||||
die "Distribution is not supported"
|
||||
fi
|
||||
if [ ! -f /etc/debian_version ]
|
||||
then
|
||||
die "Debian is supported only"
|
||||
fi
|
||||
if ! grep -q 'Linux 12' /etc/issue
|
||||
then
|
||||
die "Linux 12 (bookworm) is supported only"x
|
||||
fi
|
||||
}
|
||||
|
||||
function check_config {
|
||||
print_info "config check..."
|
||||
# Check for required parameters
|
||||
if [ -z "$db_pass" ]
|
||||
then
|
||||
die "db_pass not set in $configfile"
|
||||
fi
|
||||
if [ -z "$le_domain" ]
|
||||
then
|
||||
die "le_domain not set in $configfile"
|
||||
fi
|
||||
}
|
||||
|
||||
function die {
|
||||
echo "ERROR: $1" > /dev/null 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
function update_upgrade {
|
||||
print_info "updated and upgrade..."
|
||||
# Run through the apt-get update/upgrade first. This should be done before
|
||||
# we try to install any package
|
||||
apt-get -q -y update && apt-get -q -y dist-upgrade && apt-get -q -y autoremove
|
||||
print_info "updated and upgraded linux"
|
||||
}
|
||||
|
||||
function nocheck_install {
|
||||
# export DEBIAN_FRONTEND=noninteractive ... answers from the package configuration database
|
||||
# - q ... without progress information
|
||||
# - y ... answer interactive questions with "yes"
|
||||
# DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -q -y install $2
|
||||
# DEBIAN_FRONTEND=noninteractive apt-get --install-suggests -q -y install $1
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -q -y install $1
|
||||
print_info "installed $1"
|
||||
}
|
||||
|
||||
|
||||
function print_info {
|
||||
echo -n -e '\e[1;34m'
|
||||
echo -n $1
|
||||
echo -e '\e[0m'
|
||||
}
|
||||
|
||||
function print_warn {
|
||||
echo -n -e '\e[1;31m'
|
||||
echo -n $1
|
||||
echo -e '\e[0m'
|
||||
}
|
||||
|
||||
function stop_zotserver {
|
||||
print_info "stopping apache..."
|
||||
systemctl stop apache2
|
||||
print_info "stopping mysql db..."
|
||||
systemctl stop mariadb
|
||||
}
|
||||
|
||||
function install_apache {
|
||||
print_info "installing apache..."
|
||||
nocheck_install "apache2 apache2-utils"
|
||||
a2enmod rewrite
|
||||
systemctl restart apache2
|
||||
}
|
||||
|
||||
function install_imagemagick {
|
||||
print_info "installing imagemagick..."
|
||||
nocheck_install "imagemagick"
|
||||
}
|
||||
|
||||
function install_curl {
|
||||
print_info "installing curl..."
|
||||
nocheck_install "curl"
|
||||
}
|
||||
|
||||
function install_wget {
|
||||
print_info "installing wget..."
|
||||
nocheck_install "wget"
|
||||
}
|
||||
|
||||
function install_sendmail {
|
||||
print_info "installing sendmail..."
|
||||
nocheck_install "sendmail sendmail-bin"
|
||||
}
|
||||
|
||||
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"
|
||||
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
|
||||
}
|
||||
|
||||
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');"
|
||||
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
||||
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
|
||||
then
|
||||
>&2 echo 'ERROR: Invalid installer checksum'
|
||||
rm composer-setup.php
|
||||
die 'ERROR: Invalid installer checksum'
|
||||
fi
|
||||
php composer-setup.php --quiet
|
||||
RESULT=$?
|
||||
rm composer-setup.php
|
||||
# exit $RESULT
|
||||
# We install Composer globally
|
||||
mv composer.phar /usr/local/bin/composer
|
||||
print_info "Composer was successfully downloaded."
|
||||
else
|
||||
print_info "Composer is already downloaded on this system."
|
||||
fi
|
||||
cd $install_path
|
||||
export COMPOSER_ALLOW_SUPERUSER=1;
|
||||
/usr/local/bin/composer install --no-dev
|
||||
/usr/local/bin/composer show
|
||||
export COMPOSER_ALLOW_SUPERUSER=0;
|
||||
}
|
||||
|
||||
|
||||
function install_mysql {
|
||||
print_info "installing mysql..."
|
||||
if [ -z "$mysqlpass" ]
|
||||
then
|
||||
die "mysqlpass not set in $configfile"
|
||||
fi
|
||||
if type mysql ; then
|
||||
echo "Yes, mysql is installed"
|
||||
else
|
||||
echo "mariadb-server"
|
||||
nocheck_install "mariadb-server"
|
||||
systemctl status mariadb
|
||||
systemctl start mariadb
|
||||
mysql --user=root <<_EOF_
|
||||
UPDATE mysql.user SET Password=PASSWORD('${mysqlpass}') WHERE User='root';
|
||||
DELETE FROM mysql.user WHERE User='';
|
||||
DROP DATABASE IF EXISTS test;
|
||||
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
|
||||
FLUSH PRIVILEGES;
|
||||
_EOF_
|
||||
fi
|
||||
}
|
||||
|
||||
function install_adminer {
|
||||
print_info "installing adminer..."
|
||||
nocheck_install "adminer"
|
||||
if [ ! -f /etc/adminer/adminer.conf ]
|
||||
then
|
||||
echo "Alias /adminer /usr/share/adminer/adminer" > /etc/adminer/adminer.conf
|
||||
ln -s /etc/adminer/adminer.conf /etc/apache2/conf-available/adminer.conf
|
||||
else
|
||||
print_info "file /etc/adminer/adminer.conf exists already"
|
||||
fi
|
||||
|
||||
a2enmod rewrite
|
||||
|
||||
if [ ! -f /etc/apache2/apache2.conf ]
|
||||
then
|
||||
die "could not find file /etc/apache2/apache2.conf"
|
||||
fi
|
||||
sed -i \
|
||||
"s/AllowOverride None/AllowOverride all/" \
|
||||
/etc/apache2/apache2.conf
|
||||
|
||||
a2enconf adminer
|
||||
systemctl restart mariadb
|
||||
systemctl reload apache2
|
||||
}
|
||||
|
||||
function create_zotserver_db {
|
||||
print_info "creating zotserver database..."
|
||||
if [ -z "$db_name" ]
|
||||
then
|
||||
die "db_name not set in $configfile"
|
||||
fi
|
||||
if [ -z "$db_user" ]
|
||||
then
|
||||
die "db_user not set in $configfile"
|
||||
fi
|
||||
if [ -z "$db_pass" ]
|
||||
then
|
||||
die "db_pass not set in $configfile"
|
||||
fi
|
||||
systemctl restart mariadb
|
||||
# Make sure we don't write over an already existing database if we install more than one Zot hub/instance
|
||||
if [ -z $(mysql -h localhost -u root -p$mysqlpass -e "SHOW DATABASES;" | grep $db_name) ]
|
||||
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';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
else
|
||||
echo "database $db_name does exist already"
|
||||
fi
|
||||
}
|
||||
|
||||
function run_freedns {
|
||||
print_info "run freedns (dynamic IP)..."
|
||||
if [ -z "$freedns_key" ]
|
||||
then
|
||||
print_info "freedns was not started because 'freedns_key' is empty in $configfile"
|
||||
else
|
||||
if [ -n "$selfhost_user" ]
|
||||
then
|
||||
die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)"
|
||||
fi
|
||||
wget --no-check-certificate -O - http://freedns.afraid.org/dynamic/update.php?$freedns_key
|
||||
fi
|
||||
}
|
||||
|
||||
function install_run_selfhost {
|
||||
print_info "install and start selfhost (dynamic IP)..."
|
||||
if [ -z "$selfhost_user" ]
|
||||
then
|
||||
print_info "selfHOST was not started because 'selfhost_user' is empty in $configfile"
|
||||
else
|
||||
if [ -n "$freedns_key" ]
|
||||
then
|
||||
die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)"
|
||||
fi
|
||||
if [ -z "$selfhost_pass" ]
|
||||
then
|
||||
die "selfHOST was not started because 'selfhost_pass' is empty in $configfile"
|
||||
fi
|
||||
if [ ! -d $selfhostdir ]
|
||||
then
|
||||
mkdir $selfhostdir
|
||||
fi
|
||||
# the old way
|
||||
# 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
|
||||
bash $selfhostdir/$selfhostscript update
|
||||
fi
|
||||
}
|
||||
|
||||
function ping_domain {
|
||||
print_info "ping domain $domain..."
|
||||
# Is the domain resolved? Try to ping 6 times à 10 seconds
|
||||
COUNTER=0
|
||||
for i in {1..6}
|
||||
do
|
||||
print_info "loop $i for ping -c 1 $domain ..."
|
||||
if ping -c 4 -W 1 $le_domain
|
||||
then
|
||||
print_info "$le_domain resolved"
|
||||
break
|
||||
else
|
||||
if [ $i -gt 5 ]
|
||||
then
|
||||
die "Failed to: ping -c 1 $domain not resolved"
|
||||
fi
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
sleep 5
|
||||
}
|
||||
|
||||
function configure_cron_freedns {
|
||||
print_info "configure cron for freedns..."
|
||||
if [ -z "$freedns_key" ]
|
||||
then
|
||||
print_info "freedns is not configured because freedns_key is empty in $configfile"
|
||||
else
|
||||
# Use cron for dynamich ip update
|
||||
# - at reboot
|
||||
# - every 30 minutes
|
||||
if [ -z "`grep 'freedns.afraid.org' /etc/crontab`" ]
|
||||
then
|
||||
echo "@reboot root http://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
|
||||
echo "*/30 * * * * root wget --no-check-certificate -O - http://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
|
||||
else
|
||||
print_info "cron for freedns was configured already"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function configure_cron_selfhost {
|
||||
print_info "configure cron for selfhost..."
|
||||
if [ -z "$selfhost_user" ]
|
||||
then
|
||||
print_info "selfhost is not configured because selfhost_key is empty in $configfile"
|
||||
else
|
||||
# Use cron for dynamich ip update
|
||||
# - at reboot
|
||||
# - every 5 minutes
|
||||
if [ -z "`grep 'selfhost-updater.sh' /etc/crontab`" ]
|
||||
then
|
||||
echo "@reboot root bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab
|
||||
echo "*/5 * * * * root /bin/bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab
|
||||
else
|
||||
print_info "cron for selfhost was configured already"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function install_letsencrypt {
|
||||
print_info "installing let's encrypt ..."
|
||||
# check if user gave domain
|
||||
if [ -z "$le_domain" ]
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
||||
fi
|
||||
if [ -z "$le_email" ]
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||
fi
|
||||
nocheck_install "certbot python-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
|
||||
}
|
||||
|
||||
function check_https {
|
||||
print_info "checking httpS > testing ..."
|
||||
url_https=https://$le_domain
|
||||
wget_output=$(wget -nv --spider --max-redirect 0 $url_https)
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
print_warn "check not ok"
|
||||
else
|
||||
print_info "check ok"
|
||||
fi
|
||||
}
|
||||
|
||||
function install_zotserver {
|
||||
print_info "installing addons..."
|
||||
cd $install_path
|
||||
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
|
||||
mkdir -p "store/[data]/smarty3"
|
||||
# chmod -R 777 store
|
||||
touch .htconfig.php
|
||||
# The next run of $cron_job (daily-update script) will correct the permissions of the next line
|
||||
chmod ou+w .htconfig.php
|
||||
cd /var/www/
|
||||
chown -R www-data:www-data $install_path
|
||||
chown root:www-data $install_path/
|
||||
chown root:www-data $install_path/.htaccess
|
||||
chmod 0644 $install_path/.htaccess
|
||||
print_info "installed addons"
|
||||
}
|
||||
|
||||
function configure_cron_daily {
|
||||
print_info "configuring cron..."
|
||||
# every 10 min for poller.php
|
||||
if [ -z "`grep 'php Zotlabs/Daemon/Master.php' /etc/crontab`" ]
|
||||
then
|
||||
echo "*/10 * * * * www-data cd $install_path; php Zotlabs/Daemon/Master.php Cron >> /dev/null 2>&1" >> /etc/crontab
|
||||
fi
|
||||
# Run external script daily at 05:30
|
||||
# - stop apache/nginx and mysql-server
|
||||
# - renew the certificate of letsencrypt
|
||||
# - update repository core and addon
|
||||
# - update and upgrade linux
|
||||
# - reboot is done by "shutdown -h now" because "reboot" hangs sometimes depending on the system
|
||||
echo "#!/bin/sh" > /var/www/$cron_job
|
||||
echo "#" >> /var/www/$cron_job
|
||||
echo "echo \" \"" >> /var/www/$cron_job
|
||||
echo "echo \"+++ \$(date) +++\"" >> /var/www/$cron_job
|
||||
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 "#" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$cron_job
|
||||
echo "certbot renew --noninteractive" >> /var/www/$cron_job
|
||||
echo "#" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - db size...\"" >> /var/www/$cron_job
|
||||
echo "du -h /var/lib/mysql/ | grep mysql/" >> /var/www/$cron_job
|
||||
echo "#" >> /var/www/$cron_job
|
||||
echo "# update of $le_domain Zot hub/instance" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - updating core and addons...\"" >> /var/www/$cron_job
|
||||
echo "echo \"reaching git repository for $le_domain $zotserver hub/instance...\"" >> /var/www/$cron_job
|
||||
echo "(cd $install_path ; util/udall)" >> /var/www/$cron_job
|
||||
echo "chown -R www-data:www-data $install_path # make all accessible for the webserver" >> /var/www/$cron_job
|
||||
echo "chown root:www-data $install_path/.htaccess" >> /var/www/$cron_job
|
||||
echo "chmod 0644 $install_path/.htaccess # www-data can read but not write it" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - updating linux...\"" >> /var/www/$cron_job
|
||||
echo "apt-get -q -y update && apt-get -q -y dist-upgrade && apt-get -q -y autoremove # update linux and upgrade" >> /var/www/$cron_job
|
||||
echo "echo \"\$(date) - Update finished. Rebooting...\"" >> /var/www/$cron_job
|
||||
echo "#" >> /var/www/$cron_job
|
||||
echo "shutdown -r now" >> /var/www/$cron_job
|
||||
|
||||
chmod a+x /var/www/$cron_job
|
||||
|
||||
# If global cron job does not exist we add it to /etc/crontab
|
||||
if grep -q $cron_job /etc/crontab
|
||||
then
|
||||
echo "cron job already in /etc/crontab"
|
||||
else
|
||||
echo "30 05 * * * root /bin/bash /var/www/$cron_job >> /var/www/daily-updates.log 2>&1" >> /etc/crontab
|
||||
echo "0 0 1 * * root rm /var/www/daily-updates.log" >> /etc/crontab
|
||||
fi
|
||||
|
||||
# This is active after either "reboot" or cron reload"
|
||||
systemctl restart cron
|
||||
print_info "configured cron for updates/upgrades"
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# START OF PROGRAM
|
||||
########################################################################
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
||||
check_sanity
|
||||
|
||||
print_info "We're installing a $zotserver instance"
|
||||
install_path="$(dirname "$(pwd)")"
|
||||
|
||||
# Read config file edited by user
|
||||
configfile=config.txt
|
||||
source $configfile
|
||||
|
||||
selfhostdir=/etc/selfhost
|
||||
selfhostscript=selfhost-updater.sh
|
||||
cron_job="cron_job.sh"
|
||||
|
||||
#set -x # activate debugging from here
|
||||
|
||||
zotserver=hubzilla
|
||||
check_config
|
||||
stop_zotserver
|
||||
update_upgrade
|
||||
install_curl
|
||||
install_wget
|
||||
install_sendmail
|
||||
install_apache
|
||||
install_imagemagick
|
||||
install_php
|
||||
install_composer
|
||||
install_mysql
|
||||
install_adminer
|
||||
create_zotserver_db
|
||||
run_freedns
|
||||
install_run_selfhost
|
||||
ping_domain
|
||||
configure_cron_freedns
|
||||
configure_cron_selfhost
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_letsencrypt
|
||||
check_https
|
||||
else
|
||||
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
|
||||
fi
|
||||
|
||||
install_zotserver
|
||||
|
||||
configure_cron_daily
|
||||
|
||||
|
||||
#set +x # stop debugging from here
|
||||
33
.gitignore
vendored
33
.gitignore
vendored
@@ -49,6 +49,8 @@ doc/html/
|
||||
# external repositories for themes/addons
|
||||
extend/
|
||||
# files generated by phpunit
|
||||
tests/.cache
|
||||
tests/.phpunit.result.cache
|
||||
tests/results/
|
||||
|
||||
## exclude IDE files
|
||||
@@ -78,5 +80,36 @@ composer.phar
|
||||
vendor/**/tests/
|
||||
vendor/**/Test/
|
||||
vendor/sabre/*/examples/
|
||||
|
||||
# Exclude dev dependencies
|
||||
vendor/bin/pdepend
|
||||
vendor/bin/php-parse
|
||||
vendor/bin/phpcbf
|
||||
vendor/bin/phpcs
|
||||
vendor/bin/phpmd
|
||||
vendor/bin/phpunit
|
||||
vendor/composer/pcre/
|
||||
vendor/composer/xdebug-handler/
|
||||
vendor/dms/
|
||||
vendor/doctrine/
|
||||
vendor/myclabs/
|
||||
vendor/nikic/
|
||||
vendor/pdepend/
|
||||
vendor/phar-io/
|
||||
vendor/php-mock/
|
||||
vendor/phpmd/
|
||||
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/
|
||||
|
||||
178
.gitlab-ci.yml
178
.gitlab-ci.yml
@@ -1,10 +1,3 @@
|
||||
# Select image from https://hub.docker.com/_/php/
|
||||
#image: php:7.3
|
||||
# Use a prepared Hubzilla image to optimise pipeline duration
|
||||
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
|
||||
image: php:8.0
|
||||
|
||||
stages:
|
||||
- test
|
||||
- deploy
|
||||
@@ -24,6 +17,7 @@ variables:
|
||||
# Ignore a Composer warning
|
||||
COMPOSER_ALLOW_SUPERUSER: 1
|
||||
# Configure MySQL/MariaDB service (https://hub.docker.com/_/mysql/, https://hub.docker.com/_/mariadb/)
|
||||
DB_HOST: mysql
|
||||
MYSQL_DATABASE: hello_world_test
|
||||
MYSQL_ROOT_PASSWORD: mysql
|
||||
# Configure PostgreSQL service (https://hub.docker.com/_/postgres/)
|
||||
@@ -33,59 +27,69 @@ variables:
|
||||
|
||||
|
||||
before_script:
|
||||
# pecl and composer do not work with PHP production restrictions (from Hubzilla Docker image)
|
||||
- if [ -f /usr/local/etc/php/conf.d/z_prod.ini ]; then mv /usr/local/etc/php/conf.d/z_prod.ini /usr/local/etc/php/conf.d/z_prod.ini.off; fi
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- pecl install xdebug
|
||||
- apt-get update
|
||||
- apt-get install zip unzip libjpeg-dev libpng-dev -yqq
|
||||
- docker-php-ext-enable xdebug
|
||||
- docker-php-ext-install gd
|
||||
|
||||
|
||||
# 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 PHP
|
||||
.job_template_php: &job_definition_php
|
||||
stage: test
|
||||
script:
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
# 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
|
||||
# script:
|
||||
# - echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
# - echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
# - echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
# - vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
.job_template_mysql: &job_definition_mysql
|
||||
stage: test
|
||||
variables:
|
||||
HZ_TEST_DB_HOST: $DB_HOST
|
||||
HZ_TEST_DB_TYPE: mysql
|
||||
HZ_TEST_DB_USER: root
|
||||
HZ_TEST_DB_PASS: $MYSQL_ROOT_PASSWORD
|
||||
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"
|
||||
# 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"
|
||||
# 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=$?
|
||||
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
|
||||
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
|
||||
|
||||
|
||||
# hidden job definition with template for PostgreSQL
|
||||
#.job_template_postgres: &job_definition_postgres
|
||||
# stage: test
|
||||
# services:
|
||||
# - postgres:latest
|
||||
# script:
|
||||
# - export PGPASSWORD=$POSTGRES_PASSWORD
|
||||
# - psql --version
|
||||
# - psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
|
||||
# Import hubzilla's DB schema
|
||||
# - psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
|
||||
# Show databases and relations/tables of hubzilla's database
|
||||
#- psql -h "postgres" -U "$POSTGRES_USER" -l
|
||||
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
|
||||
# Run the actual tests
|
||||
# - vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
|
||||
.job_template_postgres: &job_definition_postgres
|
||||
stage: test
|
||||
variables:
|
||||
HZ_TEST_DB_HOST: postgres
|
||||
HZ_TEST_DB_TYPE: postgres
|
||||
HZ_TEST_DB_USER: $POSTGRES_USER
|
||||
HZ_TEST_DB_PASS: $POSTGRES_PASSWORD
|
||||
HZ_TEST_DB_DATABASE: $POSTGRES_DB
|
||||
script:
|
||||
- export PGPASSWORD=$POSTGRES_PASSWORD
|
||||
- psql --version
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
|
||||
# Import hubzilla's DB schema
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
|
||||
# Show databases and relations/tables of hubzilla's database
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -l
|
||||
- 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=$?
|
||||
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
|
||||
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
|
||||
|
||||
# hidden job definition with artifacts config template
|
||||
.artifacts_template:
|
||||
artifacts: &artifacts_template
|
||||
.artifacts_template: &artifacts_template
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
# Gitlab should show the results, but has problems parsing PHPUnit's junit file.
|
||||
reports:
|
||||
@@ -96,54 +100,30 @@ before_script:
|
||||
- tests/results/
|
||||
|
||||
|
||||
# PHP8.0
|
||||
php8.0:
|
||||
<<: *job_definition_php
|
||||
# PHP8.1 with MySQL 8.0
|
||||
php8.1_mysql8.0.22:
|
||||
image: php:8.1
|
||||
services:
|
||||
- mysql:8.0
|
||||
<<: *job_definition_mysql
|
||||
<<: *artifacts_template
|
||||
|
||||
# PHP8.0 with MySQL 5.7
|
||||
#php8.0_mysql5.7:
|
||||
# <<: *job_definition_mysql
|
||||
# services:
|
||||
# - mysql:5.7
|
||||
# PHP8.1 with MariaDB 10.6
|
||||
php8.1_mariadb10.6:
|
||||
image: php:8.1
|
||||
services:
|
||||
- name: mariadb:10.6
|
||||
alias: mysql
|
||||
<<: *job_definition_mysql
|
||||
<<: *artifacts_template
|
||||
|
||||
|
||||
# PHP8.0 with MySQL 8 (latest)
|
||||
#php8.0_mysql8:
|
||||
# <<: *job_definition_mysql
|
||||
# services:
|
||||
# - name: mysql:8
|
||||
# command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
|
||||
|
||||
# PHP8.0 with MariaDB 10.2
|
||||
#php8.0_mariadb10.2:
|
||||
# <<: *job_definition_mysql
|
||||
# services:
|
||||
# - name: mariadb:10.2
|
||||
# alias: mysql
|
||||
|
||||
|
||||
# PHP8.0 with MariaDB 10.3 (latest)
|
||||
#php8.0_mariadb10.3:
|
||||
# <<: *job_definition_mysql
|
||||
# image: php:8.0
|
||||
#image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
# services:
|
||||
# - name: mariadb:10.3
|
||||
# alias: mysql
|
||||
|
||||
|
||||
# PHP7.3 with PostgreSQL latest (11)
|
||||
#php7.3_postgres11:
|
||||
# <<: *job_definition_postgres
|
||||
# artifacts: *artifacts_template
|
||||
|
||||
|
||||
# PHP7.3 with PostgreSQL latest (11)
|
||||
#php7.3_postgres11:
|
||||
# <<: *job_definition_postgres
|
||||
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
# artifacts: *artifacts_template
|
||||
# PHP8.1 with PostgreSQL 12
|
||||
php8.1_postgres12:
|
||||
image: php:8.1
|
||||
services:
|
||||
- postgres:12-alpine
|
||||
<<: *job_definition_postgres
|
||||
<<: *artifacts_template
|
||||
|
||||
|
||||
# Generate Doxygen API Documentation and deploy it as GitLab pages
|
||||
|
||||
@@ -25,10 +25,10 @@ AddType audio/ogg .oga
|
||||
# in CGI mode.
|
||||
|
||||
RewriteCond %{REQUEST_URI} ^/\.well\-known/.*
|
||||
RewriteRule ^(.*)$ index.php?q=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
|
||||
RewriteRule ^(.*)$ index.php?q=$1 "[E=REMOTE_USER:%{HTTP:Authorization},L,QSA,B= ?]"
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?q=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
|
||||
RewriteRule ^(.*)$ index.php?q=$1 "[E=REMOTE_USER:%{HTTP:Authorization},L,QSA,B= ?]"
|
||||
</IfModule>
|
||||
|
||||
|
||||
82
.phpcs.xml
Normal file
82
.phpcs.xml
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
name="PHP_CodeSniffer"
|
||||
xsi:noNamespaceSchemaLocation="phpcs.xsd"
|
||||
>
|
||||
|
||||
<description>PHP CodeSniffer config for Hubzilla</description>
|
||||
|
||||
<file>app</file>
|
||||
<file>boot.php</file>
|
||||
<file>include</file>
|
||||
<file>index.php</file>
|
||||
<file>install</file>
|
||||
<file>library</file>
|
||||
<file>tests</file>
|
||||
<file>util</file>
|
||||
<file>view</file>
|
||||
<file>Zotlabs</file>
|
||||
|
||||
<rule ref="Generic">
|
||||
<exclude name="Generic.Arrays.ArrayIndent"/>
|
||||
<exclude name="Generic.Arrays.DisallowLongArraySyntax"/>
|
||||
<exclude name="Generic.Arrays.DisallowShortArraySyntax"/>
|
||||
<exclude name="Generic.Files.EndFileNoNewline"/>
|
||||
<exclude name="Generic.Files.LowercasedFilename"/>
|
||||
<exclude name="Generic.Formatting.MultipleStatementAlignment"/>
|
||||
<exclude name="Generic.Formatting.SpaceAfterNot"/>
|
||||
<exclude name="Generic.Functions.FunctionCallArgumentSpacing"/>
|
||||
<exclude name="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
|
||||
<exclude name="Generic.NamingConventions.CamelCapsFunctionName"/>
|
||||
<exclude name="Generic.PHP.ClosingPHPTag"/>
|
||||
<exclude name="Generic.PHP.RequireStrictTypes"/>
|
||||
<exclude name="Generic.PHP.UpperCaseConstant"/>
|
||||
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
|
||||
<exclude name="Generic.WhiteSpace.ScopeIndent"/>
|
||||
<exclude name="Generic.Commenting.DocComment.ContentAfterOpen"/>
|
||||
<exclude name="Generic.Commenting.DocComment.ContentBeforeClose"/>
|
||||
<exclude name="Generic.Commenting.DocComment.LongNotCapital"/>
|
||||
<exclude name="Generic.Commenting.DocComment.MissingShort"/>
|
||||
<exclude name="Generic.Commenting.DocComment.NonParamGroup"/>
|
||||
<exclude name="Generic.Commenting.DocComment.ParamNotFirst"/>
|
||||
<exclude name="Generic.Commenting.DocComment.ShortNotCapital"/>
|
||||
<exclude name="Generic.Commenting.DocComment.SpacingAfter"/>
|
||||
<exclude name="Generic.Commenting.DocComment.SpacingBeforeShort"/>
|
||||
<exclude name="Generic.Commenting.DocComment.TagValueIndent"/>
|
||||
<exclude name="Generic.ControlStructures.InlineControlStructure.NotAllowed"/>
|
||||
<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>
|
||||
|
||||
<!--
|
||||
Warn about lines longer than 100 columns, lines longer than 150
|
||||
columns will flag an error.
|
||||
-->
|
||||
<rule ref="Generic.Files.LineLength">
|
||||
<properties>
|
||||
<property name="lineLimit" value="100" />
|
||||
<property name="absoluteLineLimit" value="150" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!--
|
||||
Mark deprecated functions.
|
||||
-->
|
||||
<rule ref="Generic.PHP.DeprecatedFunctions">
|
||||
<properties>
|
||||
<property name="forbiddenFunctions" type="array" extend="true">
|
||||
<element key="load_config" value="Zotlabs\Lib\Config::Load" />
|
||||
<element key="get_config" value="Zotlabs\Lib\Config::Get" />
|
||||
<element key="set_config" value="Zotlabs\Lib\Config::Set" />
|
||||
<element key="del_config" value="Zotlabs\Lib\Config::Delete" />
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
867
CHANGELOG
867
CHANGELOG
@@ -1,3 +1,870 @@
|
||||
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
|
||||
- Allow uploading to comments if ocap tokens are enabled
|
||||
- Refactor get_security_ids() to remove legacy code
|
||||
- Add privacy scope sql to item_permissions_sql()
|
||||
- Removed fork awesome in favour of bootstrap icons
|
||||
- Improved content and comment collapse/expand rendering
|
||||
- Add support for inbound locations
|
||||
- Streamline item location rendering (use icon)
|
||||
- Fix html2bbcode table and add test
|
||||
- Store info/notice messages in xconfig instead of session
|
||||
- Refactor help and add tests
|
||||
- Do not run set_linkified_perms() if editing a post
|
||||
- Remove deprecated tag_deliver permissions
|
||||
- Make sure that tgroup_check() fails for group posts if they do not have the post_wall permission
|
||||
- Show repeat button to channel owners only
|
||||
- Refactor item buttons
|
||||
- Add util/update_db
|
||||
- Remove the unused f argument in various places
|
||||
- Streamline URLs used in attachments and body to ease deduplication
|
||||
- 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
|
||||
- Socialauth: update version and contact details
|
||||
- Socialauth: fix rendering issue
|
||||
|
||||
Hubzilla 9.2.1 (2024-07-18)
|
||||
- Fix fatal error if gd function image{jpeg, png, webp}() does not exist for some reason
|
||||
- Add missing pdl for mod import
|
||||
- Escape queueworker json data
|
||||
- Fix missing object when repeating own posts
|
||||
- Improve display of system notifications in relation with page reloads
|
||||
- Add possibility to only display system notifications with notifications widget
|
||||
- Fix layout issue with socialauth addon
|
||||
- Save a db lookup if we have just reset notifications in sse addon
|
||||
- Fix php error if attachment was an empty string in pubcrawl addon
|
||||
|
||||
|
||||
Hubzilla 9.2 (2024-07-06)
|
||||
- Fail to import more gracefully if a channel has already been imported at some point but was deleted again
|
||||
- Use the doubleleft template by default for admin pages to work around some display issues
|
||||
- Reflect the censored state in the local xchan
|
||||
- Exclude toplevel posts by censored channels in the public stream
|
||||
- Update API docs for Module test case base class
|
||||
- Add helper expectRedirectTo to module test class
|
||||
- Refactor is_local_url() and add api doc
|
||||
- Use empty() to check if array entry exist in create_identity()
|
||||
- Add basic test for create_identity function
|
||||
- Allow passing callable as array to hooks
|
||||
- Use DbaTransaction class for db transactions in queueworker
|
||||
- Remove obsolete stubs from Permissions tests
|
||||
- Refactor mod rpost to fix open redirect issue and add tests
|
||||
- Configure system.baseurl for tests
|
||||
- Add basic test and fix session access for mod rpost
|
||||
- Add config file and rules for PHP Code Sniffer
|
||||
- Refactor mod setup
|
||||
- Pass the force argument to the xchan_photo daemon
|
||||
- Declare arg and return types for unparse_url()
|
||||
- Skip checking MFA status for WebDAV and CardDAV requests
|
||||
- Upgrade test framework to PHPUnit 10.5
|
||||
- Minor style update for the .abook-self CSS class
|
||||
- Update docs on tags and mentions.
|
||||
- Refactor and cleanup Rbmark module and add tests
|
||||
- Remove unused Toggle_(safesearch|mobile) modules
|
||||
- Make mod regate return to system.workflow_channel_next
|
||||
- Show register message field only if registration is set to register_approve
|
||||
- Add bbcode support for the HTML5 del tag
|
||||
- Rename HelpHelper to HelpHelperTrait
|
||||
- Remove jgrowl in favour of bootstrap toast
|
||||
- Refactor mod help
|
||||
- Reduce some global state and add some docs
|
||||
- Make save_chunk() deal with userfile and file array keys
|
||||
- Update siteinfo to remove traces of zotlabs.org
|
||||
- Minor refactor for in mod import and store import host for possible later use
|
||||
- Allow to kick off import sync process in case it did not start at all
|
||||
- Updated spanish translations
|
||||
|
||||
Bugfixes
|
||||
- Fix possible PHP error in zid()
|
||||
- Fix display issue for doubleleft template
|
||||
- Fix issue where event items were parsed multiple times on display
|
||||
- Fix return to blank page after editing post under some circumstances
|
||||
- Fix missing include in QueueWorker
|
||||
- Fix warnings exposed by tests
|
||||
- Fix timestamp handling in menu_create()
|
||||
- Fix updated arg not supported in pconfig wrapper function
|
||||
- Fix default timeouts for z_(fetch|post)_url
|
||||
- Fix hcard addon markup not available if profile entries were missing
|
||||
- Fix nested lists parsing
|
||||
- Fix help menu CSS
|
||||
- Fix get_rpost_path() broken for URL's with no port
|
||||
- Fix passing an empty filter to deliverable_abook_xchans() will return all deliverable abook xchans
|
||||
|
||||
Addons
|
||||
- Wiki: fix revert if editor is not ace
|
||||
- Wiki: do not slate deleted wiki pages for download
|
||||
- Pubcrawl: do not use mentions for addressing if post is restricted
|
||||
|
||||
|
||||
Hubzilla 9.0.2 (2024-06-07)
|
||||
- Fix buttons in event viewer
|
||||
- Fix some PHP warnings and errors
|
||||
- Fix issue when inReplyTo field is an array
|
||||
- Fix possible queueworker crash
|
||||
- Fix missing pdl file for mod home
|
||||
- Reduced default directory result set
|
||||
- Fix fatal error in likebanner addon
|
||||
- Fix fatal error in hilite addon
|
||||
|
||||
|
||||
Hubzilla 9.0.1 (2024-03-26)
|
||||
- Fix an issue where after an update initiated from a modal the modal backdrop would remain
|
||||
- Fix bootstrap namespace in conv list templates
|
||||
- Fix link to delivery report in conv list templates
|
||||
- Slightly improved handling of linefeeds in some bbcode block elements and added tests
|
||||
- Fix categories_widget() cache not being observer aware
|
||||
- Allow to run additional site specific commands at the end of util/udall in util/udall_extra
|
||||
- Fix linefeeds in table and list content removed
|
||||
- Pubcrawl: do not attrmpt to sign wall to wall messages - they will appear misattributed in mastodons
|
||||
- Pubcrawl: default to Note activity type for now
|
||||
|
||||
|
||||
Hubzilla 9.0 (2024-03-22)
|
||||
- Refactor browser to browser encryption based on sodium plus library
|
||||
- Added developer docs for the refactored test system
|
||||
- Move escape_tags() to Lib/Text::escape_tags() and add test
|
||||
- Messages are now sent as articles instead of notes - this can be configured for activitypub
|
||||
- Implement support for custom emojis
|
||||
- Add test for Lib/Activity::get_textfield()
|
||||
- Refactor mod things to be AS2 compliant
|
||||
- Implement basic bbcode tests and minor refactor
|
||||
- Refactor profile activities to be AS2 complient
|
||||
- Removed poke and moods app
|
||||
- Cleanup deprecated/unused activity types
|
||||
- Update doxygen config for generating online API docs
|
||||
- Make DBA driver transaction aware
|
||||
- Deprecate internal usage of ActivityStreams1 in favor of ActivityStreams2
|
||||
- Introduce Lib/Activity::get_actor() force flag to omit cache
|
||||
- Refactor mod contactedit refresh
|
||||
- Require intl PHP extension
|
||||
- Improved checks in Web/HTTPSig::find_headers()
|
||||
- Implement custom sass bootstrap builds for channels and site
|
||||
- Mark items verified in zot delivery if either JSalmon, LDSignature or EddsaSignature verified
|
||||
- Added support for code blocks with language in markdown and html
|
||||
- Improved conversation item design
|
||||
- Start using uuid for internal reference instead of base64 encoded mid
|
||||
- Store seen mids in session instead of cache
|
||||
- Increase sess_data DB column to medium text
|
||||
- Introduce Lib/Activity::init_background_fetch()
|
||||
- Refactor zotconvo daemon
|
||||
- Implement short time object cache to reduce network calls (performance)
|
||||
- Refactor Lib/Activity::fetch_and_store_parents()
|
||||
- Introduce the fetchparents daemon
|
||||
- Refactor Libzot::process_delivery()
|
||||
- Start processing source xchan in xchan_query()
|
||||
- Added CI job for MariaDB 10.6
|
||||
- Store the original announce actor (the one that pushed the item into our stream first) in source_xchan instead of owner_xchan to preserve the original owner
|
||||
- Added optional circle person avatar
|
||||
- Added min supported DB backends to administrator docs: MySql v >= 8.0.22, MariaDB v >= 10.6, PostgreSql v >= 12
|
||||
- Added CI job for MySql 8.0
|
||||
- Improved validate_email()
|
||||
- Implement fep-8b32 - object integrity proofs
|
||||
- Implement native repeats
|
||||
- Updated spanish strings
|
||||
- Add tests for check_account_email()
|
||||
- Vastly improved unit tests including the database
|
||||
- Require sodium PHP extension
|
||||
- Require bcmath or gmp PHP extension
|
||||
- Deprecate simplepie idna_convert()
|
||||
- Update apache rewite rule to fix issue with recent apache versions - issue #1822
|
||||
- Display selected mid in an open state - issue #1425
|
||||
- Add bookmark and category to AP schema
|
||||
|
||||
Bugfixes
|
||||
- Fix cover photos not uploaded into folder due to missing source option
|
||||
- Fix regression where config returned default value in some cases
|
||||
- Fix attachments listed in reverse order
|
||||
- Fix unterminated entity reference error when dealing with domxpath and add a test
|
||||
- Fix obsolete system language selector in admin/site
|
||||
- Fix imagick readImageBlob() exception not handled
|
||||
- Fix content not moved to new location if folder was renamed via webdav
|
||||
- Fix bootstrap namespaces not up-to-date in htmlpurifier
|
||||
- Fix inReplyTo field in Lib/Activity not dealing with arrays
|
||||
- Fix round buttons not being round
|
||||
- Fix import from ical if timezone was not set in the source data
|
||||
- Fix hard linebreaks from markdown and html not preserved in bbcode conversion
|
||||
- Fix indentation from markdown and html not preserved in bbcode conversion
|
||||
- Fix images with alt text from markdown and not preserved in bbcode conversion
|
||||
- Fix custom emoji reactions arriving from pleroma
|
||||
- Fix issue where if an item is created and deleted again before the notifier has completed the queueworker will dismiss the delete because it looks like a duplicate entry
|
||||
- Fix handling HTML entities via mbstring is deprecated
|
||||
- Fix various PHP deprecation warnings
|
||||
- Fix apache rewite rule to fix issue with recent apache versions - issue #1822
|
||||
- Fix display selected mid in an open state - issue #1425
|
||||
|
||||
Addons
|
||||
- Removed smileybutton addon
|
||||
- Removed smiley_pack addon
|
||||
- Pubcrawl: refactor presentation of encrypted messages
|
||||
- Removed deprecated cryptojs addon
|
||||
- Removed emojione addon
|
||||
- New addon emoji which can provide different emoji sets via config.system.emoji_set variable - emojitwo (default), openmoji, mutant are currently supported
|
||||
- Removed addon moremoods
|
||||
- Removed addon morepokes
|
||||
- Pubcrawl: implement actor_refetch hook
|
||||
- Diaspora: implement actor_refetch hook
|
||||
- Navbanner_options: fix PHP warnings
|
||||
- Pubcrawl: add assertionMethod to encode_person()
|
||||
- Socialauth: cleanup unused files
|
||||
- Openstreetmap: adjust URLs
|
||||
|
||||
|
||||
Hubzilla 8.8.8 (2024-02-29)
|
||||
- Streams compatibility fixes
|
||||
|
||||
|
||||
Hubzilla 8.8.7 (2024-01-19)
|
||||
- Fix regression in Activity::actor_store()
|
||||
|
||||
|
||||
Hubzilla 8.8.6 (2024-01-11)
|
||||
- Provide more builtin jsonld files
|
||||
- Development branch compatibility in Libsync
|
||||
|
||||
|
||||
Hubzilla 8.8.5 (2024-01-01)
|
||||
- Fix possible loop if DB is not reachable (introduced in 8.8.3)
|
||||
- Fix some errors and deprecation warnings with PHP 8.2
|
||||
- Deprecate simplepie idna_convert in favor of PHP native function
|
||||
- Fix double processed quoted strings in get_tags()
|
||||
|
||||
|
||||
Hubzilla 8.8.4 (2023-12-20)
|
||||
- Fix regression introduced in version 8.8.3
|
||||
- Add test for Lib/Config
|
||||
- Add active addons and blocked sites to siteinfo
|
||||
|
||||
|
||||
Hubzilla 8.8.3 (2023-12-17)
|
||||
- Check return from Config::Load() and retry on failure
|
||||
- Libzot::import() do not prozess items where we could not fetch the author
|
||||
- Translation updates for Norwegian Bokmål (nb_NO)
|
||||
- Add the app terms before syncing, otherwise the terms will be reset at the other end
|
||||
- Addon statistics: deprecate nodeinfo 1.0 and implement nodeinfo 2.1
|
||||
- Addon cards: fix PHP error
|
||||
|
||||
|
||||
Hubzilla 8.8.2 (2023-12-06)
|
||||
- Fix missing includes - issue #1820
|
||||
- Addon logger_stats: improved performance reading big log files
|
||||
|
||||
|
||||
Hubzilla 8.8.1 (2023-11-27)
|
||||
- Fix error in cards addon
|
||||
- Fix error in articles addon
|
||||
- Fix double left and right template css
|
||||
|
||||
|
||||
Hubzilla 8.8 (2023-11-25)
|
||||
- Add additional observer and channel info for nav templates
|
||||
- Do not provide confidential channel info for templates
|
||||
- Add link to profile to vcard
|
||||
- Improved switch colors for better visibility
|
||||
- Raise cache.v column from text to mediumtext for MYSQL
|
||||
- Implement low level support for native repeats
|
||||
- Color mode related code moved to theme_init.php in redbasic
|
||||
- Do not overrule default list style when parsing bbcode
|
||||
- Introduce Activity::get_actor() which will check for the cache record in xconfig before fetching
|
||||
- Refactor Activity::actor_store()
|
||||
- Use new language detect library which supports many more languages
|
||||
- Use Activity::encode_person() instead of plain xchan_url to set attributedTo
|
||||
- Update composer libraries
|
||||
- Move right aside into bottom of left aside if screen width is < 1200px in redbasic
|
||||
- When parsing events, use event object in first place and use the body bbcode as backup
|
||||
- Make OWA compatible with mastodon style keyId
|
||||
- Add sourced item events to the channel calendar
|
||||
- Make activity filter widget portable to other modules
|
||||
- Deprecate remains of the unused $a variable which has been replaced by the App class ages ago
|
||||
- Return object instead of json string in the custom jsonld document loader
|
||||
- Only show theme switch icon if switching is supported by the theme
|
||||
- Store the actor cache date with the actor record so we can easily invalidate it after a period of time
|
||||
- Allow themes to manipulate app icons (photos) via hook
|
||||
- Also look for widgets in view/theme/themename/widget
|
||||
- Cache seen pubstream item mids so that they can be hidden from notifications
|
||||
- Theme fixes to make barebones bootstrap themes work slightly better
|
||||
- Update Norwegian Bokmål strings
|
||||
- Update Spanish strings
|
||||
- Transparent background for colorbox controls icons
|
||||
- Use body background color for colorboxes in redbasic
|
||||
|
||||
Bugfixes
|
||||
- Remove fragment from actor urls
|
||||
- HTTPsig case insensitive digest algorithm
|
||||
- Fix possible privacy mismatch when processing zot requests
|
||||
- Fix @someone in URL turned into mention in some situations - issue #1816
|
||||
- Fix fatal error in simplepie with PHP8.2
|
||||
- Fix tools visible allthough permission has been revoked for observer in files app
|
||||
- Fix updates entry not removed if a channel was removed
|
||||
- Fix form reset button not visible in mod rpost
|
||||
- Fix missing columns for updates table in install script
|
||||
- Fix for item widget not respecting ACL if added by title - issue #1799
|
||||
- Fix sabre/dav caldav php warnings
|
||||
- Fix public stream comments/reactions not allowed if item_fetched is set
|
||||
|
||||
Addons
|
||||
- Superblock: fix php warnings
|
||||
- Pubcrawl: restrict mod ap_probe to admin and add checkbox for signed requests
|
||||
- Wiki: fix wiki_list widget not registered
|
||||
- Deprecate remains of the unused $a variable which has been replaced by the App class ages ago
|
||||
- Pubcrawl: reflect core delivery changes for repeated items
|
||||
- Cart fix regression
|
||||
- Logger_stats: new addon for admins to track hub activities
|
||||
- Pubcrawl: check if we have the record in the short term cache before actually fetching it
|
||||
- Pubcrawl: reflect core changes to Activity::actor_store()
|
||||
- Gallery: update to photoswipe 5
|
||||
- Pubcrawl: some platforms are sending activities without an object - return error 400
|
||||
- HSSE: update sce-editor to latest version
|
||||
- SSE: sse: do not process items that are older than last login date or in case we are not logged in older than 10 minutes
|
||||
- Faces: new addon for face recognision in uploaded photos
|
||||
|
||||
|
||||
Hubzilla 8.6.3 (2023-09-16)
|
||||
- Fix regression in jsonld_document_loader()
|
||||
- Improve type checking for announce activities
|
||||
- Improve query in drop_item() to prevent possible memory exhaustion
|
||||
- Addon gallery: only add gallery code if the module is supported
|
||||
- Addon hsse: port to bootstrap 5 namespaces - core issue #1793
|
||||
|
||||
|
||||
Hubzilla 8.6.2 (2023-08-27)
|
||||
- Fix public stream comments/reactions fetching
|
||||
- Fix notification text for likes in cases where obj.actor is not set
|
||||
- Fix missing pdl file for mod cover_photo
|
||||
- Fix unable to create folders with name 0
|
||||
- Fix index name mixup in mysql schema file
|
||||
- Fix missing semicolon in mysql schema file
|
||||
- Removed unused variable
|
||||
- Fix typo in manifest
|
||||
- Fix cached jsonld files fetched via network
|
||||
- Page rendering performance improvements
|
||||
- Fix internal follow activity possibly creating notification items
|
||||
- Fix admin table highlight color for dark mode
|
||||
- Pubcrawl: do not handle not implemented listen activity
|
||||
- Diaspora: fix unshare not implemented
|
||||
|
||||
|
||||
Hubzilla 8.6.1 (2023-07-18)
|
||||
- Fix diaspora discovery
|
||||
|
||||
|
||||
Hubzilla 8.6 (2023-07-11)
|
||||
- Update fullcalendar library
|
||||
- Improve and unify selection of deliverable abook xchans
|
||||
- Remove unused pseudo_abook()
|
||||
- Implement optional moderation for unsolicited items
|
||||
- Hardened comment permission handling for unsolicited items
|
||||
- Remove unused templates
|
||||
- Deprecate ActivityStreams::fetch() and provide the possibility to fetch local items directly
|
||||
- Add simplified version of automated install script
|
||||
- Shuffle queue deliveries for more randomness
|
||||
- Update composer libraries
|
||||
- Add new 2-column templates
|
||||
- Implement optional OCAP for items to allow access to restricted media without OWA
|
||||
|
||||
Bugfixes
|
||||
- Fix content in nobb and noparse text linkified - issue #1776
|
||||
- Fix editing an event changes the set time - issue #1771
|
||||
- Fix person object with mixed up hubloc info - issue #1770
|
||||
- Fix $escape variable not passed on to stringify_array_elms()
|
||||
- Fix relaying and syncing in Activity::drop()
|
||||
- Fix allow code not sticking after channel sync - issue #1769
|
||||
- Fix channel oembed regressions
|
||||
|
||||
Addons
|
||||
- Diaspora: fix signature check for likes
|
||||
- Diaspora: fix relaying retractions
|
||||
- Diaspora: port to core unsolicited comments option
|
||||
- Gallery: add an exception for streams reshares
|
||||
- Pubcrawl: dismiss comments that are expected to arrive via owner relay
|
||||
- Pubcrawl: improved inbox handling
|
||||
- Pubcrawl: catch gup.pe updates to followers collection
|
||||
- Pubcrawl: fix follow allow hook
|
||||
- Diaspora: fix follow allow hook
|
||||
- Content_import: fix crash in post handler
|
||||
- Pubcrawl: store follow url when fetching webfinger
|
||||
- Diaspora: store follow url when fetching webfinger
|
||||
- Pubcrawl: move addressing to separate function
|
||||
|
||||
|
||||
Hubzilla 8.4.2 (2023-06-02)
|
||||
- Update bootstrap to stable version 5.3.0
|
||||
- Fix hubloc confusion in mod rmagic
|
||||
- Improved unseen forums notification
|
||||
- Add workaround for friendica accept header bug for nginx
|
||||
- Fix acl not set correctly in attach_store()
|
||||
- Fix attachment name parsing
|
||||
- Fix display issue in oembed video template
|
||||
- content_import: fix crash in post handler
|
||||
- pubcrawl: move addressing to separate function
|
||||
|
||||
|
||||
Hubzilla 8.4.1 (2023-05-20)
|
||||
- Fix issue where accepting AP contacts would reset send stream permission
|
||||
- Fix link to release page in upgrade info addon
|
||||
|
||||
|
||||
Hubzilla 8.4 (2023-05-17)
|
||||
- Slightly rewrite Activity::store() to save a query
|
||||
- Use act->objprop() in decode_note() to get activity values
|
||||
- Make sure to re-discover a channel upon connecting if we have just an xchan but no hubloc
|
||||
- Updated ES translations
|
||||
- Updated RU translations
|
||||
- Redesigned profile vcard to implement cover images
|
||||
- Slightly improved discovery of AP quoted messages
|
||||
- Updated bootstrap library
|
||||
- Changed hashtag encoding to match mastodons expectations (issue #1750)
|
||||
- Implement fedearted directory flags from trusted directory servers
|
||||
- Use Activity::get_actor_hublocs() in Libzot::fetch_conversation() instead of custom queries
|
||||
- Add the conversation endpoint
|
||||
- Implement paginated fetch for zot requests in mod item
|
||||
- Implement Zotconvo daemon to fetch conversations in the background
|
||||
- Expose deleted channels to webfinger (otherwise we can not mark them deleted locally)
|
||||
- Expire items in batches to prevent memory exhaustion
|
||||
- Remove legacy zot compatibility tweaks
|
||||
- Rewrite and simplify directory sync
|
||||
- Improve potentially long running sql query finding the thread parent
|
||||
- Implement option to override permissions for posts with mentions
|
||||
|
||||
Bugfixes
|
||||
- Fix parent_mid and thr_parent not set correctly for response activities
|
||||
- Fix query for postgres in attach_list_files()
|
||||
- Fix item_url_replace() failing on arrays
|
||||
- Fix OWA compatibility with friendica
|
||||
- Fix regression in decoding the object type
|
||||
- Fix xss vulnerability in justified gallery library
|
||||
- Fix permissions not initialized after accepted follow request from AP
|
||||
- Fix empty path passed to fopen()
|
||||
- Fix % value in format_poll() not rounded
|
||||
- Fix remove_all_xchan_resources() executed for local channels
|
||||
- Fix likes not synced via libsync between clones
|
||||
|
||||
Addons
|
||||
- Pubcrawl: fix xchan_url used as follow object instead of xchan_hash
|
||||
- Channelreputation: moved to unmaintained repo due to duplication issues when storing data in pconfig
|
||||
- Pubcrawl: add lemmy accept/reject follow quirks
|
||||
- Diaspora: handle 4xx return codes in queue management
|
||||
- Diaspora: fix fatal error in the case where parent_guid is set but empty
|
||||
- Pubcrawl: if shared inbox delivery fails deliver to contacts instead of everybody we know from that site
|
||||
- Articles: fix PHP error
|
||||
- Diaspora: rewrite synced (from a clone) item author to primary
|
||||
- Diaspora: improve reshare detection
|
||||
- Diaspora: fix contact role not sets
|
||||
- Pubcrawl: rewrite synced (from a clone) item author to primary
|
||||
- Pubcrawl: if we receive a public message to the shared inbox deliver to following *and* directly addressed
|
||||
|
||||
|
||||
Hubzilla 8.2 (2023-03-19)
|
||||
- Remove redundant untranslated htconfig templates
|
||||
- Implement workaround for friendica image/attachment construct
|
||||
- Implement notification exception for forum posts repeated by group actors
|
||||
- Updated es translations
|
||||
- Rewrite totp multifactor auth and move it from addon to core (ported from streams)
|
||||
- Implement page load progress indicator for pwa standalone mode
|
||||
- Improved mod HQ logic to save some DB lookups
|
||||
- Default owner_xchan to sender in Activity::store() except for fetched items
|
||||
- Improved contact search
|
||||
- Do not force new thread if announce comes from group actor
|
||||
- Disable oembed in notes app
|
||||
- Improved queue handling
|
||||
- Slightly restructure conv item head
|
||||
- Implemet author images in HQ widget
|
||||
- Implement author filter in HQ widget
|
||||
- Add config option db_skip_locked_supported which should be set if the DB backend supports skip locked
|
||||
- Updated simple pie library
|
||||
- Updated smarty library
|
||||
- Updated forkawesome library
|
||||
- Updated fullcalendar library
|
||||
- Implement native dark/light mode in favour of dark/light schema
|
||||
- Updated bootstrap library
|
||||
|
||||
Bugfixes
|
||||
- Fix channel calendar location html not interpreted - issue #1728
|
||||
- Fix max oembed size check if content length header is an array
|
||||
- Fix group actor wall posts turned into direct messages when posting article or card
|
||||
- Fix non zot profile mentions using zrl tag
|
||||
- Fix message filter > and < not decoded
|
||||
- Fix deleted hublocs included in author lookup
|
||||
- Fix some more PHP warnings
|
||||
- Fix syntax for get_compund_property()
|
||||
- Fix xchan_pubforum not set on actor updates
|
||||
- Fix duplicate directory entries for xchans with bogus second primary entry
|
||||
- Fix missing created timestamp in like activity - issue #1729
|
||||
- Fix messages not signed when posting from non primary locations
|
||||
- Fix pinned post regression
|
||||
- Fix autocomplete items not selectable on mobile
|
||||
- Fix hubloc confusion in Libzot::fetch_conversation()
|
||||
- Fix valid duplicate notification entries deduplicated
|
||||
- Fix ics file import
|
||||
- Fix recipients deduplication in some places
|
||||
- Fix hashtag encoded with href instead of id
|
||||
|
||||
Addons
|
||||
- Pubcrawl: re-implement encrypted content which got lost in transition
|
||||
- Pubcrawl: flag fetched items
|
||||
- Totp: removed from addons in favor of implementation in core
|
||||
- Pubcrawl: fix delivery issues for relayed activities
|
||||
- Cart: fix missing bootstrap namespace
|
||||
- Gallery: do not inject gallery code in webpages
|
||||
- Pubcrawl: fix sql error if mentions string is empty
|
||||
- Cart: fix paypal order hash size
|
||||
|
||||
|
||||
Hubzilla 8.0 (2023-01-13)
|
||||
- Updated ru strings
|
||||
- Implement ability to edit addon PDL with pdledit_gui and pdledit
|
||||
- Implement queueworker auto sleep time
|
||||
- Always add sys channel to receivers for public items
|
||||
- Improved server sent events loop
|
||||
- Exclude not tagable xchan networks handle_tag()
|
||||
- Add mark html tag to the html2bbcode parser
|
||||
- Embed or attach uploaded files depending on file type
|
||||
- Changed logic to enable site only public stream - please revisit admin setting
|
||||
- Updated nb-no strings
|
||||
- Moved queueworker to core
|
||||
- Provide a PDL file for mod invite and set the profile
|
||||
- Disabled outdated context help
|
||||
- Mark unseen items seen after a certain amount of time (default 90 days)
|
||||
- Slightly restructure lib webfinger
|
||||
- Improved redbasic dark schema
|
||||
- Implement unseen thread and unseen items count in HQ widget
|
||||
- In unseen items notifications just count the first 99 and display 99+ if there are more
|
||||
|
||||
Bugfixes
|
||||
- Fix race conditions when processing multiple choice polls
|
||||
- Fix affinity slider updates - issue #1714
|
||||
- Fix issue where accounts created with a did2 could change their password
|
||||
- Fix no message displayed if file not found in mod cloud
|
||||
- Fix pubstream tagcloud unthreaded view
|
||||
- Fix french invite template
|
||||
- Fix comment permission issue in site only public stream
|
||||
- Fix privacy tag not referring to latest hubloc entry
|
||||
- Fix selected item not highlighted
|
||||
- Fix poll issue when special chars and spaces are involved
|
||||
- Fix prune_hub_reinstalls() to only care about zot6 hublocs
|
||||
- Fix redis session PHP warnings
|
||||
- Fix remote visitor photo uploads
|
||||
- Fix mod shredwithme not showing any items
|
||||
- Fix api_auth not referring to latest hubloc entry
|
||||
- Fix category widget URLs
|
||||
- Fix poller always polling broken feeds
|
||||
- Fix sse event always triggered if public stream notification are off or the app is not installed
|
||||
- Fix more PHP8 warnings
|
||||
- Fix wrong variable in tag_deliver()
|
||||
- Fix mod follow use trim() after punify() - issue #1698
|
||||
|
||||
Addons
|
||||
- Cards: update widget info
|
||||
- Articles: update widget info
|
||||
- Wiki: update widget info
|
||||
- Sse: filter apporvals
|
||||
- Cards: use html_entity_decode before purify and html2plain for summary
|
||||
- Articles: use html_entity_decode before purify and html2plain for summary
|
||||
- Wiki: use html_entity_decode before purify and html2plain for summary
|
||||
- Cards: fix comments not displayed if filter by category
|
||||
- Articles: fix comments not displayed if filter by category
|
||||
- Sse: respect the site public stream setting
|
||||
- Queueworker: moved to core
|
||||
- Pubcrawl: move db query out of foreach loop
|
||||
- Pubcrawl: add mentions and thread owner to recipients for public items
|
||||
|
||||
|
||||
Hubzilla 7.8.7 (2022-12-03)
|
||||
- Fix regression when adding feed contacts
|
||||
- Fix regression new channel calendar event not created
|
||||
|
||||
|
||||
Hubzilla 7.8.6 (2022-11-14)
|
||||
- Fix typo in boot.php
|
||||
|
||||
|
||||
Hubzilla 7.8.5 (2022-11-13)
|
||||
- Fix outbound edit activity not of type update
|
||||
- Fix mod display not falling through to fetch public item
|
||||
- Fix more PHP warnings
|
||||
- Fix regression in items_fetch() which resulted in empty atom feed
|
||||
- Pubcrawl: cleanup and slightly restructre mod inbox
|
||||
|
||||
|
||||
Hubzilla 7.8.4 (2022-11-09)
|
||||
- Fix new uuid created when editing a post
|
||||
|
||||
|
||||
Hubzilla 7.8.3 (2022-11-07)
|
||||
- Fix regression where auto created directories were not created with public permissions
|
||||
- Fix regression where pinned/featured state of apps was not displayed correctly
|
||||
|
||||
|
||||
Hubzilla 7.8.2 (2022-11-05)
|
||||
- Pubcrawl: fix regression in inbox
|
||||
- Fix display issue of shares coming from streams
|
||||
- Throw a 404 if we could not determine which channel to load
|
||||
- If we have a cached xchan/hubloc entry, make sure we fetch the latest
|
||||
- Gallery: paint the background grid with css
|
||||
|
||||
|
||||
Hubzilla 7.8.1 (2022-10-26)
|
||||
- Silence tons of PHP warnings in core
|
||||
- Catch decryption failure edgecase in receiver
|
||||
- Deal with conversation privacy mismatches in Activity::store()
|
||||
- Composer libs updates
|
||||
- Fix timeago strings not always translated
|
||||
- Fix edit link regression in cards addon
|
||||
- Fix edit link regression in article addon
|
||||
|
||||
|
||||
Hubzilla 7.8 (2022-10-10)
|
||||
- Updated spanish translations
|
||||
- Always update hubloc_updated timestamp if a hubloc is updated
|
||||
- Do better with re-installs in various situations
|
||||
- Update htconfig templates
|
||||
- Emit an info if an item is deleted manually (issue #1691)
|
||||
- Updated german translations
|
||||
- Make Activity::actor_store() fetch the actor object if none is provided
|
||||
- Check for various forms of as:Public for compatibility
|
||||
- Cleanup dark schema
|
||||
- Make use of CSS variables in redbasic
|
||||
- Implement link hover color in redbasic
|
||||
- Update to bootstrap version 5.2 which implements CSS variables
|
||||
|
||||
Bugfixes
|
||||
- Fix stream filter for polls and events does not work anymore (issue #1694)
|
||||
- Fix item menu display issue
|
||||
- Fix HQ widget displaying superblocked items
|
||||
- Fix mod poke
|
||||
- Fix link to article or card not processed correctly if umlauts are involved (issue #1687)
|
||||
- Fix mod siteinfo containing a dead link (issue #1690)
|
||||
- Fix permission issue when displaying things (issue #1686).
|
||||
- Fix check for existing profiles (issue #1688)
|
||||
- Fix modal missing for conversation settings
|
||||
- Fix missing closing div tag if there are no recent channel activities
|
||||
- Fix issue where an unkown diaspora author was not imported if the comment arrived via a relayed activity
|
||||
- Fix mangled xchan_url due to escape_tags()
|
||||
- Fix the AP url not decode bin mod search
|
||||
- Fix some php warnings
|
||||
|
||||
Addons
|
||||
- Wiki: move create_missing_page() from widget to module
|
||||
- Superblock: implement blocking for messages widget_item
|
||||
- Diaspora: fix verification of relayed comments and likes
|
||||
- Pubcrawl: make sure to store the attributedTo actor in announce activities
|
||||
- Diaspora: fix issue where an unkown author was not imported if the comment arrived via a relayed activity
|
||||
|
||||
|
||||
Hubzilla 7.6.1 (2022-08-07)
|
||||
Bugfixes
|
||||
- Fix attachments displayed in visible response activities
|
||||
- Fix wrong attribution in unseen like notifications
|
||||
|
||||
Addons
|
||||
- Cards: fix widget not implemented via pdl file (requires re-install)
|
||||
- Articles: fix widget not implemented via pdl file (requires re-install)
|
||||
- Wiki: fix widget not implemented via pdl file (requires re-install)
|
||||
|
||||
|
||||
Hubzilla 7.6 (2022-07-26)
|
||||
- Add filter rule to check for false condition
|
||||
- Implement HQ dashboard to display recently created content for various modules
|
||||
- Updated spanish translations
|
||||
- Implement a max oembed size which defaults to 1MB
|
||||
- Update composer libs
|
||||
|
||||
Addons
|
||||
- Cart: do not attempt oembed
|
||||
- Cards: implement channel_activities_widget for HQ dashboard
|
||||
- Articles: implement channel_activities_widget for HQ dashboard
|
||||
- Wiki: implement channel_activities_widget for HQ dashboard
|
||||
|
||||
Bugfixes
|
||||
- Fix language filter filtering ambigous results
|
||||
- Fix vcard-card background for dark schema
|
||||
- Fix contact edit dialog not displayed in chrome browser
|
||||
- Fix readability of category pills in dark schema
|
||||
- Fix opengraph images inside zmg opening tag
|
||||
- Fix oembed attempted for text previews
|
||||
|
||||
|
||||
Hubzilla 7.4 (2022-06-01)
|
||||
- Updated russian translations
|
||||
- Raise min PHP version to 8.0
|
||||
- Rewrite inbound attachment handling
|
||||
- Move photo flag feature from addon to core
|
||||
- Adjust default production php logging
|
||||
- Update composer libs
|
||||
- Add a hidden config to enable the hs2019 http signature algorithm
|
||||
- Allow starring of pubstream items
|
||||
- Update spanish translations
|
||||
- Add the title in forum post reshares if applicable
|
||||
- Implement inbound pleroma reactions
|
||||
- Add real name info to the navbar template data
|
||||
- Add the updated date to the icon url so that other platforms will pick it up on change
|
||||
- Move wiki from core to addon
|
||||
- Move articles from core to addon
|
||||
- Move cards from core to addon
|
||||
|
||||
Addons
|
||||
- Rendezvous: add missing default value to sql schema
|
||||
- Wiki: moved from core to addons
|
||||
- Articles: moved from core to addons
|
||||
- Cards: moved from core to addons
|
||||
- Photoflag: moved to core
|
||||
- Sse: fix issue where notifications were emited for created tasks
|
||||
|
||||
Bugfixes
|
||||
- Fix issue where inbound activitypub items lost image descriptions (issue 1679)
|
||||
- Fix issue where observer tags were not rendered correctly in event items (issue 1674)
|
||||
- Fix forum posts leaked into network stream
|
||||
- Fix tags not found in search if not logged in (issue 1677)
|
||||
- Fix dislikes causing stuck notifications (issue 1676)
|
||||
|
||||
|
||||
Hubzilla 7.2.2 (2022-04-26)
|
||||
- Fix item_verified not set due to data structure changes
|
||||
|
||||
|
||||
Hubzilla 7.2.1 (2022-04-25)
|
||||
- Fix changing profile image from new member widget - issue #1671
|
||||
- Fix regression with incoming poll answers from activitypub introduced in 7.2
|
||||
- Fix addons not removed from the DB when removed from the filesystem
|
||||
- Fix regression in attaching images for activitypub introduced in 7.2
|
||||
- Move activitypub addressing from core to the pubcrawl addon
|
||||
- Fix hub re-install issues
|
||||
- Fediwordle: slightly improved algorithm
|
||||
|
||||
|
||||
Hubzilla 7.2 (2022-03-29)
|
||||
- Streamline comment policy with downstream project
|
||||
- Add new function is_local_url()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Access;
|
||||
|
||||
|
||||
/**
|
||||
* @brief AccessList class which represents individual content ACLs.
|
||||
*
|
||||
@@ -17,29 +18,48 @@ class AccessList {
|
||||
* @brief Allow contacts
|
||||
* @var string
|
||||
*/
|
||||
private $allow_cid;
|
||||
private ?string $allow_cid;
|
||||
/**
|
||||
* @brief Allow groups
|
||||
* @var string
|
||||
*/
|
||||
private $allow_gid;
|
||||
private ?string $allow_gid;
|
||||
/**
|
||||
* @brief Deny contacts
|
||||
* @var string
|
||||
*/
|
||||
private $deny_cid;
|
||||
private ?string $deny_cid;
|
||||
/**
|
||||
* @brief Deny groups
|
||||
* @var string
|
||||
*/
|
||||
private $deny_gid;
|
||||
private ?string $deny_gid;
|
||||
/**
|
||||
* @brief Indicates if we are using the default constructor values or
|
||||
* values that have been set explicitly.
|
||||
* @var boolean
|
||||
*/
|
||||
private $explicit;
|
||||
private bool $explicit;
|
||||
|
||||
/**
|
||||
* @brief Keys required by the constructor if the channel array is given.
|
||||
*/
|
||||
private const REQUIRED_KEYS_CONSTRUCTOR = [
|
||||
'channel_allow_cid',
|
||||
'channel_allow_gid',
|
||||
'channel_deny_cid',
|
||||
'channel_deny_gid'
|
||||
];
|
||||
|
||||
/**
|
||||
* @brief Keys required by the set method.
|
||||
*/
|
||||
private const REQUIRED_KEYS_SET = [
|
||||
'allow_cid',
|
||||
'allow_gid',
|
||||
'deny_cid',
|
||||
'deny_gid'
|
||||
];
|
||||
|
||||
/**
|
||||
* @brief Constructor for AccessList class.
|
||||
@@ -53,8 +73,9 @@ class AccessList {
|
||||
* * \e string \b channel_deny_cid => string of denied cids
|
||||
* * \e string \b channel_deny_gid => string of denied gids
|
||||
*/
|
||||
function __construct($channel) {
|
||||
function __construct(array $channel) {
|
||||
if ($channel) {
|
||||
$this->validate_input_array($channel, self::REQUIRED_KEYS_CONSTRUCTOR);
|
||||
$this->allow_cid = $channel['channel_allow_cid'];
|
||||
$this->allow_gid = $channel['channel_allow_gid'];
|
||||
$this->deny_cid = $channel['channel_deny_cid'];
|
||||
@@ -70,13 +91,24 @@ class AccessList {
|
||||
$this->explicit = false;
|
||||
}
|
||||
|
||||
private function validate_input_array(array $arr, array $required_keys) : void {
|
||||
$missing_keys = array_diff($required_keys, array_keys($arr));
|
||||
|
||||
if (!empty($missing_keys)) {
|
||||
throw new \Exception(
|
||||
'Invalid AccessList object: Expected array with keys: '
|
||||
. implode(', ', $missing_keys)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get if we are using the default constructor values
|
||||
* or values that have been set explicitly.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function get_explicit() {
|
||||
function get_explicit() : bool {
|
||||
return $this->explicit;
|
||||
}
|
||||
|
||||
@@ -94,7 +126,9 @@ class AccessList {
|
||||
* * \e string \b deny_gid => string of denied gids
|
||||
* @param boolean $explicit (optional) default true
|
||||
*/
|
||||
function set($arr, $explicit = true) {
|
||||
function set(array $arr, bool $explicit = true) : void {
|
||||
$this->validate_input_array($arr, self::REQUIRED_KEYS_SET);
|
||||
|
||||
$this->allow_cid = $arr['allow_cid'];
|
||||
$this->allow_gid = $arr['allow_gid'];
|
||||
$this->deny_cid = $arr['deny_cid'];
|
||||
@@ -112,7 +146,7 @@ class AccessList {
|
||||
* * \e string \b deny_cid => string of denied cids
|
||||
* * \e string \b deny_gid => string of denied gids
|
||||
*/
|
||||
function get() {
|
||||
function get() : array {
|
||||
return [
|
||||
'allow_cid' => $this->allow_cid,
|
||||
'allow_gid' => $this->allow_gid,
|
||||
@@ -138,7 +172,12 @@ class AccessList {
|
||||
* * \e array|string \b group_deny => array with gids or comma-seperated string
|
||||
* @param boolean $explicit (optional) default true
|
||||
*/
|
||||
function set_from_array($arr, $explicit = true) {
|
||||
function set_from_array(array $arr, bool $explicit = true) : void {
|
||||
$arr['contact_allow'] = $arr['contact_allow'] ?? [];
|
||||
$arr['group_allow'] = $arr['group_allow'] ?? [];
|
||||
$arr['contact_deny'] = $arr['contact_deny'] ?? [];
|
||||
$arr['group_deny'] = $arr['group_deny'] ?? [];
|
||||
|
||||
$this->allow_cid = perms2str((is_array($arr['contact_allow']))
|
||||
? $arr['contact_allow'] : explode(',', $arr['contact_allow']));
|
||||
$this->allow_gid = perms2str((is_array($arr['group_allow']))
|
||||
@@ -156,7 +195,7 @@ class AccessList {
|
||||
*
|
||||
* @return boolean Return true if any of allow_* deny_* values is set.
|
||||
*/
|
||||
function is_private() {
|
||||
function is_private() : bool {
|
||||
return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Access;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
/**
|
||||
* @brief PermissionRoles class.
|
||||
*
|
||||
@@ -247,7 +249,7 @@ class PermissionRoles {
|
||||
break;
|
||||
}
|
||||
|
||||
$x = get_config('system','role_perms');
|
||||
$x = Config::Get('system','role_perms');
|
||||
|
||||
// let system settings over-ride any or all
|
||||
if($x && is_array($x) && array_key_exists($role,$x))
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ class Addon {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
call_hooks('daemon_addon', $argv);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@ class Cache_embeds {
|
||||
$item = $c[0];
|
||||
|
||||
// bbcode conversion by default processes embeds that aren't already cached.
|
||||
// Ignore the returned html output.
|
||||
// Ignore the returned html output.
|
||||
|
||||
bbcode($item['body']);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Cache;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Cache_query {
|
||||
|
||||
@@ -11,26 +12,31 @@ class Cache_query {
|
||||
if(! $argc == 3)
|
||||
return;
|
||||
|
||||
$r = null;
|
||||
$key = $argv[1];
|
||||
|
||||
$pid = get_config('procid', $key, false);
|
||||
$pid = Config::Get('procid', $key, false);
|
||||
if ($pid && (function_exists('posix_kill') ? posix_kill($pid, 0) : true)) {
|
||||
logger($key . ': procedure already run with pid ' . $pid, LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$pid = getmypid();
|
||||
set_config('procid', $key, $pid);
|
||||
Config::Set('procid', $key, $pid);
|
||||
|
||||
array_shift($argv);
|
||||
array_shift($argv);
|
||||
|
||||
|
||||
$arr = json_decode(base64_decode($argv[0]), true);
|
||||
|
||||
$r = call_user_func_array('q', $arr);
|
||||
if($r)
|
||||
Cache::set($key, serialize($r));
|
||||
|
||||
del_config('procid', $key);
|
||||
if(is_array($r)) {
|
||||
Cache::set($key, serialize($r));
|
||||
}
|
||||
|
||||
Config::Delete('procid', $key);
|
||||
|
||||
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);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once('include/hubloc.php');
|
||||
|
||||
class Checksites {
|
||||
@@ -10,13 +12,16 @@ class Checksites {
|
||||
|
||||
logger('checksites: start');
|
||||
|
||||
$site_id = '';
|
||||
$sql_options = '';
|
||||
|
||||
if (($argc > 1) && ($argv[1]))
|
||||
$site_id = $argv[1];
|
||||
|
||||
if ($site_id)
|
||||
$sql_options = " and site_url = '" . dbesc($argv[1]) . "' ";
|
||||
|
||||
$days = intval(get_config('system', 'sitecheckdays'));
|
||||
$days = intval(Config::Get('system', 'sitecheckdays'));
|
||||
if ($days < 1)
|
||||
$days = 30;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ class Cli_suggest {
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
update_suggestions();
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ class Convo {
|
||||
intval($channel_id),
|
||||
dbesc($contact_hash)
|
||||
);
|
||||
|
||||
if (!$r) {
|
||||
return;
|
||||
}
|
||||
@@ -40,19 +41,26 @@ class Convo {
|
||||
|
||||
$messages = $obj->get();
|
||||
|
||||
if ($messages) {
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$message = Activity::fetch($message, $channel);
|
||||
}
|
||||
// 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);
|
||||
Activity::store($channel, $contact['abook_xchan'], $AS, $item);
|
||||
}
|
||||
if (!$messages) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$message = Activity::fetch($message, $channel);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
|
||||
class Cron {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
$maxsysload = intval(get_config('system', 'maxloadavg'));
|
||||
$maxsysload = intval(Config::Get('system', 'maxloadavg'));
|
||||
if ($maxsysload < 1)
|
||||
$maxsysload = 50;
|
||||
if (function_exists('sys_getloadavg')) {
|
||||
@@ -19,10 +21,11 @@ class Cron {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
|
||||
$lockfile = 'store/[data]/cron';
|
||||
if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
|
||||
&& (!get_config('system', 'override_cron_lockfile'))) {
|
||||
&& (!Config::Get('system', 'override_cron_lockfile'))) {
|
||||
logger("cron: Already running");
|
||||
return;
|
||||
}
|
||||
@@ -30,9 +33,21 @@ class Cron {
|
||||
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
|
||||
$x = '';
|
||||
file_put_contents($lockfile, $x);
|
||||
*/
|
||||
|
||||
logger('cron: start');
|
||||
|
||||
// If this is a directory server, request a sync with an upstream
|
||||
// directory at least once a day, up to once every poll interval.
|
||||
// Pull remote changes and push local changes.
|
||||
// potential issue: how do we keep from creating an endless update loop?
|
||||
|
||||
$dirmode = Config::Get('system', 'directory_mode');
|
||||
|
||||
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
Libzotdir::sync_directories($dirmode);
|
||||
}
|
||||
|
||||
// run queue delivery process in the background
|
||||
|
||||
Master::Summon(array('Queue'));
|
||||
@@ -50,23 +65,25 @@ class Cron {
|
||||
require_once('include/account.php');
|
||||
remove_expired_registrations();
|
||||
|
||||
$interval = get_config('system', 'delivery_interval', 3);
|
||||
$interval = Config::Get('queueworker', 'queue_interval', 500000);
|
||||
|
||||
// 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)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,8 +113,10 @@ class Cron {
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
Master::Summon(array('Directory', $rr['channel_id'], 'force'));
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,13 +125,13 @@ 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(get_config('system', 'active_expire_days', '30') . ' DAY')
|
||||
db_quoteinterval(Config::Get('system', 'cache_expire_days', 7) . ' DAY')
|
||||
);
|
||||
if ($r) {
|
||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY')
|
||||
db_quoteinterval(Config::Get('system', 'cache_expire_days', 7) . ' DAY')
|
||||
);
|
||||
foreach ($r as $rr) {
|
||||
$file = dbunescbin($rr['content']);
|
||||
@@ -128,50 +147,41 @@ 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)]
|
||||
]
|
||||
);
|
||||
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']]);
|
||||
}
|
||||
Master::Summon(array('Notifier', 'wall-new', $rr['id']));
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// by directory servers
|
||||
|
||||
$d1 = intval(get_config('system', 'last_expire_day'));
|
||||
$d1 = intval(Config::Get('system', 'last_expire_day'));
|
||||
$d2 = intval(datetime_convert('UTC', 'UTC', 'now', 'd'));
|
||||
|
||||
// Allow somebody to staggger daily activities if they have more than one site on their server,
|
||||
// or if it happens at an inconvenient (busy) hour.
|
||||
|
||||
$h1 = intval(get_config('system', 'cron_hour'));
|
||||
$h1 = intval(Config::Get('system', 'cron_hour'));
|
||||
$h2 = intval(datetime_convert('UTC', 'UTC', 'now', 'G'));
|
||||
|
||||
|
||||
@@ -203,10 +213,10 @@ class Cron {
|
||||
}
|
||||
|
||||
|
||||
// pull in some public posts
|
||||
// pull in some public posts if allowed
|
||||
|
||||
$disable_discover_tab = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false;
|
||||
if (!$disable_discover_tab)
|
||||
$disable_externals = Config::Get('system', 'disable_discover_tab') || Config::Get('system', 'disable_discover_tab') === false || Config::Get('system', 'site_firehose');
|
||||
if (!$disable_externals)
|
||||
Master::Summon(['Externals']);
|
||||
|
||||
$restart = false;
|
||||
@@ -225,10 +235,10 @@ class Cron {
|
||||
if (!$restart)
|
||||
Master::Summon(array('Cronhooks'));
|
||||
|
||||
set_config('system', 'lastcron', datetime_convert());
|
||||
Config::Set('system', 'lastcron', datetime_convert());
|
||||
|
||||
//All done - clear the lockfile
|
||||
@unlink($lockfile);
|
||||
//@unlink($lockfile);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
|
||||
class Cron_daily {
|
||||
@@ -49,10 +50,26 @@ class Cron_daily {
|
||||
dbesc('sse_id.%')
|
||||
);
|
||||
|
||||
// Clean up emdedded content cache
|
||||
// Mark items seen after X days (default 90)
|
||||
|
||||
$r = dbq("select channel_id from channel where channel_removed = 0");
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$mark_seen_days = get_pconfig($rr['channel_id'], 'system', 'mark_seen_days', 90);
|
||||
q("UPDATE item SET item_unseen = 0 WHERE
|
||||
uid = %d AND item_unseen = 1
|
||||
AND created < %s - INTERVAL %s",
|
||||
intval($rr['channel_id']),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($mark_seen_days . ' DAY')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up cache
|
||||
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY')
|
||||
db_quoteinterval(Config::Get('system', 'cache_expire_days', 7) . ' DAY')
|
||||
);
|
||||
|
||||
//update statistics in config
|
||||
@@ -66,7 +83,7 @@ class Cron_daily {
|
||||
|
||||
// expire old delivery reports
|
||||
|
||||
$keep_reports = intval(get_config('system', 'expire_delivery_reports'));
|
||||
$keep_reports = intval(Config::Get('system', 'expire_delivery_reports'));
|
||||
if ($keep_reports === 0)
|
||||
$keep_reports = 10;
|
||||
|
||||
@@ -78,17 +95,6 @@ class Cron_daily {
|
||||
// expire any expired accounts
|
||||
downgrade_accounts();
|
||||
|
||||
// If this is a directory server, request a sync with an upstream
|
||||
// directory at least once a day, up to once every poll interval.
|
||||
// Pull remote changes and push local changes.
|
||||
// potential issue: how do we keep from creating an endless update loop?
|
||||
|
||||
$dirmode = get_config('system', 'directory_mode');
|
||||
|
||||
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
Libzotdir::sync_directories($dirmode);
|
||||
}
|
||||
|
||||
Master::Summon(array('Expire'));
|
||||
Master::Summon(array('Cli_suggest'));
|
||||
|
||||
@@ -98,10 +104,12 @@ class Cron_daily {
|
||||
$date = datetime_convert();
|
||||
call_hooks('cron_daily', $date);
|
||||
|
||||
set_config('system', 'last_expire_day', intval(datetime_convert('UTC', 'UTC', 'now', 'd')));
|
||||
Config::Set('system', 'last_expire_day', intval(datetime_convert('UTC', 'UTC', 'now', 'd')));
|
||||
|
||||
/**
|
||||
* End Cron Daily
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Cron_weekly {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
@@ -22,12 +24,12 @@ class Cron_weekly {
|
||||
|
||||
mark_orphan_hubsxchans();
|
||||
|
||||
// Find channels that were removed in the last three weeks, but
|
||||
// Find channels that were removed in the last three weeks, but
|
||||
// haven't been finally cleaned up. These should be older than 10
|
||||
// days to ensure that "purgeall" messages have gone out or bounced
|
||||
// or timed out.
|
||||
// days to ensure that "purgeall" messages have gone out or bounced
|
||||
// or timed out.
|
||||
|
||||
$r = q("select channel_id from channel where channel_removed = 1 and
|
||||
$r = q("select channel_id from channel where channel_removed = 1 and
|
||||
channel_deleted > %s - INTERVAL %s and channel_deleted < %s - INTERVAL %s",
|
||||
db_utcnow(), db_quoteinterval('21 DAY'),
|
||||
db_utcnow(), db_quoteinterval('10 DAY')
|
||||
@@ -44,7 +46,7 @@ class Cron_weekly {
|
||||
db_utcnow(), db_quoteinterval('14 DAY')
|
||||
);
|
||||
|
||||
$dirmode = intval(get_config('system', 'directory_mode'));
|
||||
$dirmode = intval(Config::Get('system', 'directory_mode'));
|
||||
if ($dirmode === DIRECTORY_MODE_SECONDARY || $dirmode === DIRECTORY_MODE_PRIMARY) {
|
||||
logger('regdir: ' . print_r(z_fetch_url(get_directory_primary() . '/regdir?f=&url=' . urlencode(z_root()) . '&realm=' . urlencode(get_directory_realm())), true));
|
||||
}
|
||||
@@ -59,5 +61,6 @@ class Cron_weekly {
|
||||
* End Cron Weekly
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ class Deliver {
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,12 @@ class Deliver_hooks {
|
||||
$r = q("select * from item where id = '%d'",
|
||||
intval($argv[1])
|
||||
);
|
||||
if ($r)
|
||||
|
||||
if ($r) {
|
||||
call_hooks('notifier_normal', $r[0]);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
use Zotlabs\Lib\Queue;
|
||||
@@ -25,7 +26,7 @@ class Directory {
|
||||
|
||||
logger('directory update', LOGGER_DEBUG);
|
||||
|
||||
$dirmode = get_config('system', 'directory_mode');
|
||||
$dirmode = Config::Get('system', 'directory_mode');
|
||||
if ($dirmode === false)
|
||||
$dirmode = DIRECTORY_MODE_NORMAL;
|
||||
|
||||
@@ -97,5 +98,7 @@ class Directory {
|
||||
if ($pushall) {
|
||||
Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id']));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once('include/items.php');
|
||||
|
||||
class Expire {
|
||||
@@ -10,42 +12,41 @@ class Expire {
|
||||
|
||||
cli_startup();
|
||||
|
||||
$pid = get_config('procid', 'expire', false);
|
||||
$pid = Config::Get('procid', 'expire', false);
|
||||
if ($pid && (function_exists('posix_kill') ? posix_kill($pid, 0) : true)) {
|
||||
logger('procedure already run with pid ' . $pid, LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$pid = getmypid();
|
||||
set_config('procid', 'expire', $pid);
|
||||
Config::Set('procid', 'expire', $pid);
|
||||
|
||||
// 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']);
|
||||
}
|
||||
}
|
||||
|
||||
// physically remove anything that has been deleted for more than two months
|
||||
/** @FIXME - this is a wretchedly inefficient query */
|
||||
|
||||
q("delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval('36 DAY')
|
||||
);
|
||||
|
||||
if (intval(get_config('system', 'optimize_items')))
|
||||
if (intval(Config::Get('system', 'optimize_items')))
|
||||
q("optimize table item");
|
||||
|
||||
logger('expire: start with pid ' . $pid, LOGGER_DEBUG);
|
||||
|
||||
$site_expire = intval(get_config('system', 'default_expire_days'));
|
||||
$commented_days = intval(get_config('system', 'active_expire_days'));
|
||||
$site_expire = intval(Config::Get('system', 'default_expire_days', 30));
|
||||
$commented_days = intval(Config::Get('system', 'active_expire_days', 7));
|
||||
|
||||
logger('site_expire: ' . $site_expire);
|
||||
|
||||
@@ -59,8 +60,8 @@ class Expire {
|
||||
continue;
|
||||
|
||||
// service class default (if non-zero) over-rides the site default
|
||||
|
||||
$service_class_expire = service_class_fetch($rr['channel_id'], 'expire_days');
|
||||
|
||||
if (intval($service_class_expire))
|
||||
$channel_expire = $service_class_expire;
|
||||
else
|
||||
@@ -85,8 +86,7 @@ class Expire {
|
||||
|
||||
// this should probably just fetch the channel_expire_days from the sys channel,
|
||||
// but there's no convenient way to set it.
|
||||
|
||||
$expire_days = get_config('system', 'sys_expire_days');
|
||||
$expire_days = Config::Get('system', 'sys_expire_days');
|
||||
if ($expire_days === false)
|
||||
$expire_days = 30;
|
||||
|
||||
@@ -96,12 +96,15 @@ class Expire {
|
||||
|
||||
logger('Expire: sys interval: ' . $expire_days, LOGGER_DEBUG);
|
||||
|
||||
if ($expire_days)
|
||||
if ($expire_days) {
|
||||
item_expire($x['channel_id'], $expire_days, $commented_days);
|
||||
}
|
||||
|
||||
logger('Expire: sys: done', LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
del_config('procid', 'expire');
|
||||
Config::Delete('procid', 'expire');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ class Externals {
|
||||
$importer = get_sys_channel();
|
||||
$total = 0;
|
||||
$attempts = 0;
|
||||
$url = '';
|
||||
|
||||
logger('externals: startup', LOGGER_DEBUG);
|
||||
|
||||
@@ -67,9 +68,8 @@ class Externals {
|
||||
datetime_convert('UTC', 'UTC', 'now - 30 days')
|
||||
);
|
||||
|
||||
$contact = $r[0];
|
||||
|
||||
if ($contact) {
|
||||
if ($r) {
|
||||
$contact = $r[0];
|
||||
$url = $contact['hubloc_id_url'];
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class Externals {
|
||||
continue;
|
||||
}
|
||||
|
||||
$obj_id = isset($message['object']['id']) ?? $message['object'];
|
||||
$obj_id = $message['object']['id'] ?? $message['object'];
|
||||
|
||||
Libzot::fetch_conversation($importer, $obj_id);
|
||||
$total++;
|
||||
@@ -143,7 +143,8 @@ class Externals {
|
||||
$AS = new ActivityStreams($message);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
Activity::store($importer, $contact['abook_xchan'], $AS, $item);
|
||||
$item['item_fetched'] = true;
|
||||
Activity::store($importer, $contact['hubloc_hash'], $AS, $item);
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
|
||||
42
Zotlabs/Daemon/Fetchparents.php
Normal file
42
Zotlabs/Daemon/Fetchparents.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Activity;
|
||||
|
||||
class Fetchparents {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
logger('Fetchparents invoked: ' . print_r($argv, true));
|
||||
|
||||
if ($argc < 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
$channels = explode(',', $argv[1]);
|
||||
if (!$channels) {
|
||||
return;
|
||||
}
|
||||
|
||||
$observer_hash = $argv[2];
|
||||
if (!$observer_hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
$mid = $argv[3];
|
||||
if (!$mid) {
|
||||
return;
|
||||
}
|
||||
|
||||
$force = $argv[4] ?? false;
|
||||
|
||||
foreach ($channels as $channel_id) {
|
||||
$channel = channelx_by_n($channel_id);
|
||||
Activity::fetch_and_store_parents($channel, $observer_hash, $mid, null, $force);
|
||||
}
|
||||
|
||||
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']) {
|
||||
|
||||
@@ -38,10 +38,9 @@ class Gprobe {
|
||||
|
||||
if ($url) {
|
||||
$zf = Zotfinger::exec($url, null);
|
||||
}
|
||||
|
||||
if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
|
||||
Libzot::import_xchan($zf['data']);
|
||||
if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $url && intval($zf['signature']['header_valid'])) {
|
||||
Libzot::import_xchan($zf['data']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,32 @@ class Importdoc {
|
||||
|
||||
self::update_docs_dir('doc/*');
|
||||
|
||||
// remove old files that weren't updated (indicates they were most likely deleted).
|
||||
$i = q("select id, uid from item where item_type = 5 and edited < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval('14 DAY')
|
||||
);
|
||||
|
||||
if ($i) {
|
||||
foreach ($i as $iv) {
|
||||
drop_item($iv['id'], uid: $iv['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
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') {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\QueueWorker;
|
||||
|
||||
if (array_search(__file__, get_included_files()) === 0) {
|
||||
require_once('include/cli_startup.php');
|
||||
array_shift($argv);
|
||||
@@ -9,6 +11,7 @@ if (array_search(__file__, get_included_files()) === 0) {
|
||||
|
||||
if ($argc)
|
||||
Master::Release($argc, $argv);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,6 +19,10 @@ if (array_search(__file__, get_included_files()) === 0) {
|
||||
class Master {
|
||||
|
||||
static public function Summon($arr) {
|
||||
|
||||
QueueWorker::Summon($arr);
|
||||
return;
|
||||
/*
|
||||
$hookinfo = [
|
||||
'argv' => $arr
|
||||
];
|
||||
@@ -30,13 +37,17 @@ class Master {
|
||||
return;
|
||||
}
|
||||
|
||||
$phpbin = get_config('system', 'phpbin', 'php');
|
||||
$phpbin = Config::Get('system', 'phpbin', 'php');
|
||||
proc_run($phpbin, 'Zotlabs/Daemon/Master.php', $arr);
|
||||
*/
|
||||
}
|
||||
|
||||
static public function Release($argc, $argv) {
|
||||
cli_startup();
|
||||
|
||||
QueueWorker::Release($argv);
|
||||
return;
|
||||
/*
|
||||
$hookinfo = [
|
||||
'argv' => $argv
|
||||
];
|
||||
@@ -54,5 +65,6 @@ class Master {
|
||||
logger('Master: release: ' . json_encode($argv), LOGGER_ALL, LOG_DEBUG);
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$cls::run($argc, $argv);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Queue;
|
||||
use Zotlabs\Lib\LDSignatures;
|
||||
|
||||
require_once('include/html2plain.php');
|
||||
require_once('include/conversation.php');
|
||||
@@ -79,10 +79,7 @@ class Notifier {
|
||||
static public $encoded_item = null;
|
||||
static public $channel = null;
|
||||
static public $private = false;
|
||||
// $fragment can contain additional info to omit de-duplication in the queueworker.
|
||||
// E.g. if an item is updated many times in a row from different sources (multiple vote updates) the
|
||||
// update source mid or a timestamp or random string can be added.
|
||||
static public $fragment = null;
|
||||
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
@@ -107,10 +104,15 @@ class Notifier {
|
||||
self::$encoded_item = null;
|
||||
self::$channel = null;
|
||||
self::$private = false;
|
||||
self::$fragment = null;
|
||||
|
||||
$sys = get_sys_channel();
|
||||
$normal_mode = true;
|
||||
$upstream = false;
|
||||
$uplink = false;
|
||||
$target_item = null;
|
||||
$parent_item = null;
|
||||
$top_level_post = false;
|
||||
$relay_to_owner = false;
|
||||
|
||||
if ($cmd === 'keychange') {
|
||||
self::$channel = channelx_by_n($item_id);
|
||||
@@ -227,8 +229,6 @@ class Notifier {
|
||||
|
||||
// Fetch the target item
|
||||
|
||||
self::$fragment = $argv[3] ?? '';
|
||||
|
||||
$r = q("SELECT * FROM item WHERE id = %d AND parent != 0",
|
||||
intval($item_id)
|
||||
);
|
||||
@@ -241,11 +241,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,23 +263,9 @@ 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']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) {
|
||||
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'], [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)) {
|
||||
//hz_syslog(print_r($target_item,true));
|
||||
logger('notifier: target item not forwardable', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -300,6 +281,11 @@ class Notifier {
|
||||
return;
|
||||
}
|
||||
|
||||
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'];
|
||||
}
|
||||
|
||||
if ($target_item['mid'] === $target_item['parent_mid']) {
|
||||
$parent_item = $target_item;
|
||||
$top_level_post = true;
|
||||
@@ -337,14 +323,7 @@ class Notifier {
|
||||
self::$encoded_item = json_decode($m, true);
|
||||
}
|
||||
else {
|
||||
|
||||
self::$encoded_item = array_merge(['@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1',
|
||||
z_root() . ZOT_APSCHEMA_REV
|
||||
]], Activity::encode_activity($target_item)
|
||||
);
|
||||
self::$encoded_item['signature'] = LDSignatures::sign(self::$encoded_item, self::$channel);
|
||||
self::$encoded_item = Activity::build_packet(Activity::encode_activity($target_item), self::$channel, false);
|
||||
}
|
||||
|
||||
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
|
||||
@@ -360,8 +339,6 @@ class Notifier {
|
||||
// the hostname in the message_id and provides a second (fallback) opinion.
|
||||
|
||||
$relay_to_owner = (!$top_level_post && intval($target_item['item_origin']) && comment_local_origin($target_item));
|
||||
$uplink = false;
|
||||
$upstream = 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
|
||||
@@ -393,7 +370,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;
|
||||
}
|
||||
@@ -411,9 +388,7 @@ class Notifier {
|
||||
self::$private = false;
|
||||
self::$recipients = collect_recipients($parent_item, self::$private);
|
||||
|
||||
// FIXME add any additional recipients such as mentions, etc.
|
||||
|
||||
if ($top_level_post) {
|
||||
if ($top_level_post && intval($target_item['item_wall'])) {
|
||||
// remove clones who will receive the post via sync
|
||||
self::$recipients = array_values(array_diff(self::$recipients, [$target_item['owner_xchan']]));
|
||||
}
|
||||
@@ -505,6 +480,7 @@ class Notifier {
|
||||
// public posts won't make it to the local public stream unless there's a recipient on this site.
|
||||
// This code block sees if it's a public post and localhost is missing, and if so adds an entry for the local sys channel to the $hubs list
|
||||
|
||||
/* sys channel is now added in collect recipients
|
||||
if (!self::$private) {
|
||||
$found_localhost = false;
|
||||
if ($hubs) {
|
||||
@@ -525,6 +501,7 @@ class Notifier {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (!$hubs) {
|
||||
logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
|
||||
@@ -593,8 +570,6 @@ class Notifier {
|
||||
|
||||
foreach ($dhubs as $hub) {
|
||||
|
||||
logger('notifier_hub: ' . $hub['hubloc_url'], LOGGER_DEBUG);
|
||||
|
||||
if ($hub['hubloc_network'] !== 'zot6') {
|
||||
$narr = [
|
||||
'channel' => self::$channel,
|
||||
@@ -647,13 +622,14 @@ class Notifier {
|
||||
// This shouldn't produce false positives on comment boosts that were generated on other platforms
|
||||
// because we won't be delivering them.
|
||||
|
||||
if (isset($target_item) && isset($target_item['verb']) && $target_item['verb'] === 'Announce' && $target_item['author_xchan'] === $target_item['owner_xchan'] && ! intval($target_item['item_thread_top'])) {
|
||||
if (isset($target_item['verb']) && $target_item['verb'] === 'Announce' && $target_item['author_xchan'] === $target_item['owner_xchan'] && ! intval($target_item['item_thread_top'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hash = new_uuid();
|
||||
|
||||
$env = (($hub_env && $hub_env[$hub['hubloc_site_id']]) ? $hub_env[$hub['hubloc_site_id']] : '');
|
||||
$env = $hub_env[$hub['hubloc_site_id']] ?? '';
|
||||
|
||||
if ((self::$private) && (!$env)) {
|
||||
continue;
|
||||
}
|
||||
@@ -672,7 +648,7 @@ class Notifier {
|
||||
);
|
||||
|
||||
// only create delivery reports for normal undeleted items
|
||||
if (is_array($target_item) && (!$target_item['item_deleted']) && (!get_config('system', 'disable_dreport'))) {
|
||||
if (is_array($target_item) && (!$target_item['item_deleted']) && (!Config::Get('system', 'disable_dreport'))) {
|
||||
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue )
|
||||
values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
|
||||
dbesc($target_item['mid']),
|
||||
@@ -690,11 +666,11 @@ class Notifier {
|
||||
|
||||
}
|
||||
|
||||
if ($normal_mode) {
|
||||
if ($normal_mode && is_array($target_item)) {
|
||||
// This wastes a process if there are no delivery hooks configured, so check this before launching the new process
|
||||
$x = q("select * from hook where hook = 'notifier_normal'");
|
||||
if ($x) {
|
||||
Master::Summon(['Deliver_hooks', $target_item['id'], self::$fragment]);
|
||||
Master::Summon(['Deliver_hooks', $target_item['id']]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,7 +678,7 @@ class Notifier {
|
||||
do_delivery(self::$deliveries);
|
||||
}
|
||||
|
||||
if ($dead_hosts && is_array($target_item) && (!$target_item['item_deleted']) && (!get_config('system', 'disable_dreport'))) {
|
||||
if ($dead_hosts && is_array($target_item) && (!$target_item['item_deleted']) && (!Config::Get('system', 'disable_dreport'))) {
|
||||
foreach ($dead_hosts as $deceased_host) {
|
||||
$r = q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue )
|
||||
values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
|
||||
|
||||
@@ -15,61 +15,45 @@ class Onedirsync {
|
||||
$update_id = intval($argv[1]);
|
||||
|
||||
if (!$update_id) {
|
||||
logger('onedirsync: no update');
|
||||
logger('onedirsync: no update id');
|
||||
return;
|
||||
}
|
||||
|
||||
$r = q("select * from updates where ud_id = %d limit 1",
|
||||
$r = q("select * from updates where ud_id = %d",
|
||||
intval($update_id)
|
||||
);
|
||||
|
||||
if (!$r)
|
||||
return;
|
||||
|
||||
if (($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (!$r[0]['ud_addr']))
|
||||
return;
|
||||
|
||||
// Have we probed this channel more recently than the other directory server
|
||||
// (where we received this update from) ?
|
||||
// If we have, we don't need to do anything except mark any older entries updated
|
||||
|
||||
$x = q("select * from updates where ud_addr = '%s' and ud_date > '%s' and ( ud_flags & %d )>0 order by ud_date desc limit 1",
|
||||
dbesc($r[0]['ud_addr']),
|
||||
dbesc($r[0]['ud_date']),
|
||||
intval(UPDATE_FLAGS_UPDATED)
|
||||
);
|
||||
if ($x) {
|
||||
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'",
|
||||
intval(UPDATE_FLAGS_UPDATED),
|
||||
dbesc($r[0]['ud_addr']),
|
||||
intval(UPDATE_FLAGS_UPDATED),
|
||||
dbesc($x[0]['ud_date'])
|
||||
);
|
||||
if (!$r) {
|
||||
logger('onedirsync: update id not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore doing an update if this ud_addr refers to a known dead hubloc
|
||||
|
||||
$h = q("select * from hubloc where hubloc_addr = '%s'",
|
||||
$h = q("select * from hubloc where hubloc_id_url = '%s' order by hubloc_id desc",
|
||||
dbesc($r[0]['ud_addr']),
|
||||
);
|
||||
|
||||
$h = Libzot::zot_record_preferred($h);
|
||||
|
||||
if (($h) && (($h['hubloc_status'] & HUBLOC_OFFLINE) || $h['hubloc_deleted'] || $h['hubloc_error'])) {
|
||||
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ",
|
||||
intval(UPDATE_FLAGS_DELETED),
|
||||
dbesc($r[0]['ud_addr']),
|
||||
intval(UPDATE_FLAGS_UPDATED)
|
||||
);
|
||||
return;
|
||||
|
||||
// 2023-04-12: Try to update anyway since the info is not always correct
|
||||
// This might change after all directory servers run the new code.
|
||||
|
||||
// q("update updates set ud_flags = 9 where ud_hash = '%s' and ud_flags != 9",
|
||||
// dbesc($r[0]['ud_hash'])
|
||||
//);
|
||||
|
||||
// return;
|
||||
}
|
||||
|
||||
// we might have to pull this out some day, but for now update_directory_entry()
|
||||
// runs zot_finger() and is kind of zot specific
|
||||
|
||||
if ($h && $h['hubloc_network'] !== 'zot6')
|
||||
if ($h && $h['hubloc_network'] !== 'zot6') {
|
||||
return;
|
||||
}
|
||||
|
||||
Libzotdir::update_directory_entry($r[0]);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Zotlabs\Daemon;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\ASCollection;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/socgraph.php');
|
||||
@@ -25,19 +26,15 @@ class Onepoll {
|
||||
}
|
||||
|
||||
$sql_extra = '';
|
||||
$allow_feeds = get_config('system', 'feed_contacts');
|
||||
$allow_feeds = Config::Get('system', 'feed_contacts');
|
||||
if(!$allow_feeds) {
|
||||
$sql_extra = ' and abook_feed = 0 ';
|
||||
}
|
||||
|
||||
$contacts = q("SELECT abook.*, xchan.*, account.*
|
||||
FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan
|
||||
where abook_id = %d $sql_extra
|
||||
and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0
|
||||
AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1",
|
||||
intval($contact_id),
|
||||
intval(ACCOUNT_OK),
|
||||
intval(ACCOUNT_UNVERIFIED)
|
||||
$contacts = q("SELECT abook.*, xchan.* FROM abook
|
||||
LEFT JOIN xchan ON xchan_hash = abook_xchan
|
||||
WHERE abook_id = %d",
|
||||
intval($contact_id)
|
||||
);
|
||||
|
||||
if (!$contacts) {
|
||||
@@ -46,6 +43,7 @@ class Onepoll {
|
||||
}
|
||||
|
||||
$contact = $contacts[0];
|
||||
|
||||
$importer_uid = $contact['abook_channel'];
|
||||
|
||||
$importer = channelx_by_n($importer_uid);
|
||||
@@ -53,7 +51,7 @@ class Onepoll {
|
||||
if (!$importer)
|
||||
return;
|
||||
|
||||
logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
|
||||
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))
|
||||
? datetime_convert('UTC', 'UTC', 'now - 7 days')
|
||||
@@ -63,12 +61,21 @@ class Onepoll {
|
||||
if ($contact['xchan_network'] === 'rss') {
|
||||
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
|
||||
$alive = handle_feed($importer['channel_id'], $contact_id, $contact['xchan_hash']);
|
||||
if ($alive) {
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
|
||||
if (!$alive) {
|
||||
q("update abook set abook_updated = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
q("update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,7 +126,7 @@ class Onepoll {
|
||||
|
||||
if ($fetch_feed) {
|
||||
|
||||
$max = intval(get_config('system', 'max_imported_posts', 30));
|
||||
$max = intval(Config::Get('system', 'max_imported_posts', 30));
|
||||
|
||||
if (intval($max)) {
|
||||
$cl = Activity::get_actor_collections($contact['abook_xchan']);
|
||||
@@ -162,6 +169,7 @@ class Onepoll {
|
||||
$AS = new ActivityStreams($message);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
$item['item_fetched'] = true;
|
||||
Activity::store($importer, $contact['abook_xchan'], $AS, $item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Poller {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
$maxsysload = intval(get_config('system', 'maxloadavg'));
|
||||
$maxsysload = intval(Config::Get('system', 'maxloadavg'));
|
||||
if ($maxsysload < 1)
|
||||
$maxsysload = 50;
|
||||
if (function_exists('sys_getloadavg')) {
|
||||
@@ -17,21 +19,7 @@ class Poller {
|
||||
}
|
||||
}
|
||||
|
||||
$interval = intval(get_config('system', 'poll_interval'));
|
||||
if (!$interval)
|
||||
$interval = ((get_config('system', 'delivery_interval') === false) ? 3 : intval(get_config('system', 'delivery_interval')));
|
||||
|
||||
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
|
||||
$lockfile = 'store/[data]/poller';
|
||||
if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
|
||||
&& (!get_config('system', 'override_poll_lockfile'))) {
|
||||
logger("poller: Already running");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
|
||||
$x = '';
|
||||
file_put_contents($lockfile, $x);
|
||||
$interval = Config::Get('queueworker', 'queue_interval', 500000);
|
||||
|
||||
logger('poller: start');
|
||||
|
||||
@@ -57,12 +45,17 @@ class Poller {
|
||||
reload_plugins();
|
||||
|
||||
// Only poll from those with suitable relationships
|
||||
$abandon_days = intval(get_config('system', 'account_abandon_days', 0));
|
||||
$abandon_days = intval(Config::Get('system', 'account_abandon_days', 0));
|
||||
$abandon_sql = (($abandon_days)
|
||||
? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days) . ' DAY'))
|
||||
: ''
|
||||
);
|
||||
|
||||
$allow_feeds = Config::Get('system', 'feed_contacts');
|
||||
if(!$allow_feeds) {
|
||||
$sql_extra .= ' and abook_feed = 0 ';
|
||||
}
|
||||
|
||||
$randfunc = db_getfunc('RAND');
|
||||
|
||||
$contacts = q("SELECT abook.abook_updated, abook.abook_connected, abook.abook_feed,
|
||||
@@ -72,7 +65,7 @@ class Poller {
|
||||
account.account_lastlog, account.account_flags
|
||||
FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash
|
||||
LEFT JOIN account on abook_account = account_id
|
||||
where abook_self = 0
|
||||
where abook_self = 0 and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0
|
||||
$sql_extra
|
||||
AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY $randfunc",
|
||||
intval(ACCOUNT_OK),
|
||||
@@ -90,16 +83,27 @@ class Poller {
|
||||
if (intval($contact['abook_feed'])) {
|
||||
$min = service_class_fetch($contact['abook_channel'], 'minimum_feedcheck_minutes');
|
||||
if (!$min)
|
||||
$min = intval(get_config('system', 'minimum_feedcheck_minutes'));
|
||||
$min = intval(Config::Get('system', 'minimum_feedcheck_minutes'));
|
||||
if (!$min)
|
||||
$min = 60;
|
||||
$x = datetime_convert('UTC', 'UTC', "now - $min minutes");
|
||||
if ($c < $x) {
|
||||
Master::Summon(['Onepoll', $contact['abook_id']]);
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
|
||||
if ($t !== $c) {
|
||||
// if the last fetch failed only attempt fetch once a day
|
||||
$min = 60 * 24;
|
||||
}
|
||||
|
||||
$x = datetime_convert('UTC', 'UTC', "now - $min minutes");
|
||||
|
||||
if ($t < $x) {
|
||||
Master::Summon(['Onepoll', $contact['abook_id']]);
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if ($contact['xchan_network'] !== 'zot6')
|
||||
@@ -158,20 +162,22 @@ class Poller {
|
||||
continue;
|
||||
|
||||
Master::Summon(['Onepoll', $contact['abook_id']]);
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dirmode = intval(get_config('system', 'directory_mode'));
|
||||
$dirmode = intval(Config::Get('system', 'directory_mode'));
|
||||
|
||||
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
$r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last <= '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ",
|
||||
intval(UPDATE_FLAGS_UPDATED),
|
||||
$r = q("SELECT * FROM updates WHERE ud_update = 1 AND (ud_last = '%s' OR ud_last > %s - INTERVAL %s)",
|
||||
dbesc(NULL_DATE),
|
||||
db_utcnow(), db_quoteinterval('7 DAY')
|
||||
db_utcnow(),
|
||||
db_quoteinterval('7 DAY')
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
|
||||
@@ -181,18 +187,17 @@ class Poller {
|
||||
if ($rr['ud_last'] > NULL_DATE)
|
||||
if ($rr['ud_last'] > datetime_convert('UTC', 'UTC', 'now - 1 day'))
|
||||
continue;
|
||||
|
||||
Master::Summon(['Onedirsync', $rr['ud_id']]);
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_config('system', 'lastpoll', datetime_convert());
|
||||
|
||||
//All done - clear the lockfile
|
||||
|
||||
@unlink($lockfile);
|
||||
Config::Set('system', 'lastpoll', datetime_convert());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,77 +7,59 @@ use Zotlabs\Lib\Queue as LibQueue;
|
||||
class Queue {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
require_once('include/items.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
if ($argc > 1)
|
||||
$queue_id = $argv[1];
|
||||
else
|
||||
$queue_id = EMPTY_STR;
|
||||
$queue_id = ($argc > 1) ? $argv[1] : '';
|
||||
|
||||
logger('queue: start');
|
||||
|
||||
// delete all queue items more than 3 days old
|
||||
// but first mark these sites dead if we haven't heard from them in a month
|
||||
|
||||
$r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s",
|
||||
db_utcnow(), db_quoteinterval('3 DAY')
|
||||
$oldqItems = q("select outq_posturl, outq_hash from outq where outq_created < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval('3 DAY')
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$h = parse_url($rr['outq_posturl']);
|
||||
$desturl = $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : '');
|
||||
|
||||
if ($oldqItems) {
|
||||
foreach ($oldqItems as $qItem) {
|
||||
$h = parse_url($qItem['outq_posturl']);
|
||||
$site_url = $h['scheme'] . '://' . $h['host'] . ((!empty($h['port'])) ? ':' . $h['port'] : '');
|
||||
q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s",
|
||||
dbesc($desturl),
|
||||
db_utcnow(), db_quoteinterval('1 MONTH')
|
||||
dbesc($site_url),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('1 MONTH')
|
||||
);
|
||||
}
|
||||
|
||||
$old_hashes = ids_to_querystr($oldqItems, 'outq_hash', true);
|
||||
|
||||
logger('Removing ' . count($oldqItems) . ' old queue entries');
|
||||
dbq("DELETE FROM outq WHERE outq_hash IN ($old_hashes)");
|
||||
|
||||
}
|
||||
|
||||
q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s",
|
||||
db_utcnow(), db_quoteinterval('3 DAY')
|
||||
);
|
||||
$deliveries = [];
|
||||
|
||||
if ($queue_id) {
|
||||
$r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
|
||||
$qItems = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
|
||||
dbesc($queue_id)
|
||||
);
|
||||
logger('queue deliver: ' . $qItems[0]['outq_hash'] . ' to ' . $qItems[0]['outq_posturl'], LOGGER_DEBUG);
|
||||
LibQueue::deliver($qItems[0]);
|
||||
}
|
||||
else {
|
||||
|
||||
// For the first 12 hours we'll try to deliver every 15 minutes
|
||||
// After that, we'll only attempt delivery once per hour.
|
||||
// This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
|
||||
// so that we don't start off a thousand deliveries for a couple of dead hubs.
|
||||
// The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
|
||||
// Other drivers will have to do something different here and may need their own query.
|
||||
|
||||
// Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
|
||||
// "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
|
||||
// or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
|
||||
// the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
|
||||
// or twice a day.
|
||||
|
||||
$sqlrandfunc = db_getfunc('rand');
|
||||
|
||||
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
|
||||
$qItems = q("SELECT outq_hash FROM outq WHERE outq_scheduled < %s ",
|
||||
db_utcnow()
|
||||
);
|
||||
while ($r) {
|
||||
foreach ($r as $rv) {
|
||||
LibQueue::deliver($rv);
|
||||
}
|
||||
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
|
||||
db_utcnow()
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!$r)
|
||||
return;
|
||||
|
||||
foreach ($r as $rv) {
|
||||
LibQueue::deliver($rv);
|
||||
}
|
||||
if ($qItems) {
|
||||
foreach ($qItems as $qItem) {
|
||||
$deliveries[] = $qItem['outq_hash'];
|
||||
}
|
||||
|
||||
shuffle($deliveries);
|
||||
do_delivery($deliveries, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Thumbnail {
|
||||
|
||||
@@ -19,9 +20,9 @@ class Thumbnail {
|
||||
|
||||
$attach = $c[0];
|
||||
|
||||
$preview_style = intval(get_config('system', 'thumbnail_security', 0));
|
||||
$preview_width = intval(get_config('system', 'thumbnail_width', 300));
|
||||
$preview_height = intval(get_config('system', 'thumbnail_height', 300));
|
||||
$preview_style = intval(Config::Get('system', 'thumbnail_security', 0));
|
||||
$preview_width = intval(Config::Get('system', 'thumbnail_width', 300));
|
||||
$preview_height = intval(Config::Get('system', 'thumbnail_height', 300));
|
||||
|
||||
$p = [
|
||||
'attach' => $attach,
|
||||
@@ -73,5 +74,7 @@ class Thumbnail {
|
||||
|| (filectime(dbunescbin($attach['content']) . 'thumb') < (time() - 60)))) {
|
||||
$default_controller->Thumb($attach, $preview_style, $preview_width, $preview_height);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
37
Zotlabs/Daemon/Xchan_photo.php
Normal file
37
Zotlabs/Daemon/Xchan_photo.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/** @file */
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
class Xchan_photo {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if ($argc < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = hex2bin($argv[1]);
|
||||
$xchan = hex2bin($argv[2]);
|
||||
$force = $argv[3];
|
||||
|
||||
$photos = import_xchan_photo($url, $xchan, false, $force);
|
||||
if ($photos) {
|
||||
$result = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'",
|
||||
dbescdate(datetime_convert()),
|
||||
dbesc($photos[0]),
|
||||
dbesc($photos[1]),
|
||||
dbesc($photos[2]),
|
||||
dbesc($photos[3]),
|
||||
dbesc($xchan)
|
||||
);
|
||||
|
||||
if (! $result) {
|
||||
logger("xchan photo update failed for $url");
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
37
Zotlabs/Daemon/Zotconvo.php
Normal file
37
Zotlabs/Daemon/Zotconvo.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
class Zotconvo {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
logger('Zotconvo invoked: ' . print_r($argv, true));
|
||||
|
||||
if ($argc < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
$channels = explode(',', $argv[1]);
|
||||
if (!$channels) {
|
||||
return;
|
||||
}
|
||||
|
||||
$mid = $argv[2];
|
||||
if (!$mid) {
|
||||
return;
|
||||
}
|
||||
|
||||
$force = $argv[3] ?? false;
|
||||
|
||||
foreach ($channels as $channel_id) {
|
||||
$channel = channelx_by_n($channel_id);
|
||||
Libzot::fetch_conversation($channel, $mid, $force);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
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
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Extend;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Route {
|
||||
|
||||
@@ -38,11 +39,11 @@ class Route {
|
||||
}
|
||||
|
||||
static function get() {
|
||||
return get_config('system','routes',[]);
|
||||
return Config::Get('system','routes',[]);
|
||||
}
|
||||
|
||||
static function set($r) {
|
||||
return set_config('system','routes',$r);
|
||||
return Config::Set('system','routes',$r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Extend;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Widget {
|
||||
|
||||
@@ -38,10 +39,10 @@ class Widget {
|
||||
}
|
||||
|
||||
static function get() {
|
||||
return get_config('system','widgets',[]);
|
||||
return Config::Get('system','widgets',[]);
|
||||
}
|
||||
|
||||
static function set($r) {
|
||||
return set_config('system','widgets',$r);
|
||||
return Config::Set('system','widgets',$r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Identity;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class OAuth2Server extends \OAuth2\Server {
|
||||
|
||||
public function __construct(OAuth2Storage $storage, $config = null) {
|
||||
@@ -24,8 +26,8 @@ class OAuth2Server extends \OAuth2\Server {
|
||||
|
||||
$keyStorage = new \OAuth2\Storage\Memory( [
|
||||
'keys' => [
|
||||
'public_key' => get_config('system', 'pubkey'),
|
||||
'private_key' => get_config('system', 'prvkey')
|
||||
'public_key' => Config::Get('system', 'pubkey'),
|
||||
'private_key' => Config::Get('system', 'prvkey')
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
33
Zotlabs/Lib/ASCache.php
Normal file
33
Zotlabs/Lib/ASCache.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php /** @file */
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
/**
|
||||
* A wrapper for the cache api
|
||||
*/
|
||||
|
||||
class ASCache {
|
||||
public static function isEnabled() {
|
||||
return Config::Get('system', 'as_object_cache_enabled', true);
|
||||
}
|
||||
|
||||
public static function getAge() {
|
||||
return Config::Get('system', 'as_object_cache_time', '10 MINUTE');
|
||||
}
|
||||
|
||||
public static function Get($key) {
|
||||
if (!self::isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Cache::get($key, self::getAge());
|
||||
}
|
||||
|
||||
public static function Set($key, $value) {
|
||||
if (!self::isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Cache::set($key, $value);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ class ASCollection {
|
||||
$this->direction = $direction;
|
||||
$this->limit = $limit;
|
||||
|
||||
$data = null;
|
||||
|
||||
if (is_array($obj)) {
|
||||
$data = $obj;
|
||||
}
|
||||
@@ -147,4 +149,4 @@ class ASCollection {
|
||||
}
|
||||
logger('nextpage: ' . $this->nextpage, LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,17 @@ namespace Zotlabs\Lib;
|
||||
class AbConfig {
|
||||
|
||||
static public function Load($chan,$xhash,$family = '') {
|
||||
if($family)
|
||||
$where = '';
|
||||
|
||||
if($family) {
|
||||
$where = sprintf(" and cat = '%s' ",dbesc($family));
|
||||
}
|
||||
|
||||
$r = q("select * from abconfig where chan = %d and xchan = '%s' $where",
|
||||
intval($chan),
|
||||
dbesc($xhash)
|
||||
);
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
@@ -21,7 +26,7 @@ class AbConfig {
|
||||
intval($chan),
|
||||
dbesc($xhash),
|
||||
dbesc($family),
|
||||
dbesc($key)
|
||||
dbesc($key)
|
||||
);
|
||||
if($r) {
|
||||
return ((preg_match('|^a:[0-9]+:{.*}$|s', $r[0]['v'])) ? unserialize($r[0]['v']) : $r[0]['v']);
|
||||
@@ -41,19 +46,19 @@ class AbConfig {
|
||||
dbesc($xhash),
|
||||
dbesc($family),
|
||||
dbesc($key),
|
||||
dbesc($dbvalue)
|
||||
dbesc($dbvalue)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$r = q("update abconfig set v = '%s' where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
|
||||
dbesc($dbvalue),
|
||||
dbesc($dbvalue),
|
||||
dbesc($chan),
|
||||
dbesc($xhash),
|
||||
dbesc($family),
|
||||
dbesc($key)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if($r)
|
||||
return $value;
|
||||
return false;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@ class ActivityStreams {
|
||||
public $meta = null;
|
||||
public $valid = false;
|
||||
public $deleted = false;
|
||||
public $portable_id = null;
|
||||
public $id = '';
|
||||
public $parent_id = '';
|
||||
public $type = '';
|
||||
@@ -23,10 +24,11 @@ class ActivityStreams {
|
||||
public $origin = null;
|
||||
public $owner = null;
|
||||
public $signer = null;
|
||||
public $ldsig = null;
|
||||
public $sig = null;
|
||||
public $sigok = false;
|
||||
public $recips = null;
|
||||
public $raw_recips = null;
|
||||
public $saved_recips = null;
|
||||
|
||||
/**
|
||||
* @brief Constructor for ActivityStreams.
|
||||
@@ -35,12 +37,13 @@ class ActivityStreams {
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
function __construct($string) {
|
||||
function __construct($string, $portable_id = null) {
|
||||
|
||||
if(!$string)
|
||||
return;
|
||||
|
||||
$this->raw = $string;
|
||||
$this->portable_id = $portable_id;
|
||||
|
||||
if (is_array($string)) {
|
||||
$this->data = $string;
|
||||
@@ -70,9 +73,12 @@ class ActivityStreams {
|
||||
}
|
||||
}
|
||||
|
||||
// This indicates only that we have sucessfully decoded JSON.
|
||||
$this->valid = true;
|
||||
|
||||
if (array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) {
|
||||
// Special handling for Mastodon "delete actor" activities which will often fail to verify
|
||||
// because the key cannot be fetched. We will catch this condition elsewhere.
|
||||
if (is_array($this->data) && array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) {
|
||||
if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
|
||||
$this->deleted = $this->data['actor'];
|
||||
$this->valid = false;
|
||||
@@ -81,8 +87,18 @@ class ActivityStreams {
|
||||
|
||||
}
|
||||
|
||||
// Attempt to assemble an Activity from what we were given.
|
||||
if ($this->is_valid()) {
|
||||
$this->id = $this->get_property_obj('id');
|
||||
$this->id = $this->get_property_obj('id');
|
||||
|
||||
if (!$this->id) {
|
||||
logger('Data with mmissing id: ' . print_r($this->data, true));
|
||||
return;
|
||||
}
|
||||
|
||||
// cache for future use
|
||||
ASCache::Set($this->id, 'json:' . $this->raw);
|
||||
|
||||
$this->type = $this->get_primary_type();
|
||||
$this->actor = $this->get_actor('actor', '', '');
|
||||
$this->obj = $this->get_compound_property('object');
|
||||
@@ -90,11 +106,19 @@ class ActivityStreams {
|
||||
$this->origin = $this->get_compound_property('origin');
|
||||
$this->recips = $this->collect_recips();
|
||||
|
||||
$this->ldsig = $this->get_compound_property('signature');
|
||||
if ($this->ldsig) {
|
||||
$this->signer = $this->get_actor('creator', $this->ldsig);
|
||||
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
|
||||
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
|
||||
$this->sig = $this->get_compound_property('proof');
|
||||
if ($this->sig) {
|
||||
$this->checkEddsaSignature(); // will set signer and sigok if everything works out
|
||||
}
|
||||
|
||||
// Try LDSignatures if edsig failed
|
||||
if (!$this->sigok) {
|
||||
$this->sig = $this->get_compound_property('signature');
|
||||
if ($this->sig) {
|
||||
$this->signer = $this->get_actor('creator', $this->sig);
|
||||
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
|
||||
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,25 +130,34 @@ class ActivityStreams {
|
||||
}
|
||||
}
|
||||
|
||||
// fetch recursive or embedded activities
|
||||
// Fetch recursive or embedded activities
|
||||
|
||||
if ($this->obj && is_array($this->obj) && array_key_exists('object', $this->obj)) {
|
||||
$this->obj['object'] = $this->get_compound_property($this->obj['object']);
|
||||
$this->obj['object'] = $this->get_compound_property('object', $this->obj);
|
||||
}
|
||||
|
||||
if ($this->obj && is_array($this->obj) && $this->obj['actor'])
|
||||
// Enumerate and store actors in referenced objects
|
||||
|
||||
if ($this->obj && is_array($this->obj) && isset($this->obj['actor'])) {
|
||||
$this->obj['actor'] = $this->get_actor('actor', $this->obj);
|
||||
if ($this->tgt && is_array($this->tgt) && $this->tgt['actor'])
|
||||
$this->tgt['actor'] = $this->get_actor('actor', $this->tgt);
|
||||
|
||||
$this->parent_id = $this->get_property_obj('inReplyTo');
|
||||
|
||||
if ((!$this->parent_id) && is_array($this->obj)) {
|
||||
$this->parent_id = $this->obj['inReplyTo'];
|
||||
}
|
||||
if ((!$this->parent_id) && is_array($this->obj)) {
|
||||
|
||||
if ($this->tgt && is_array($this->tgt) && isset($this->tgt['actor'])) {
|
||||
$this->tgt['actor'] = $this->get_actor('actor', $this->tgt);
|
||||
}
|
||||
|
||||
// Determine if this is a followup or response activity
|
||||
|
||||
$this->parent_id = ((is_array($this->get_property_obj('inReplyTo'))) ? $this->get_property_obj('inReplyTo')['id'] : $this->get_property_obj('inReplyTo'));
|
||||
|
||||
if (!$this->parent_id && isset($this->obj['inReplyTo'])) {
|
||||
$this->parent_id = ((is_array($this->obj['inReplyTo'])) ? $this->obj['inReplyTo']['id'] : $this->obj['inReplyTo']);
|
||||
}
|
||||
|
||||
if (!$this->parent_id && isset($this->obj['id'])) {
|
||||
$this->parent_id = $this->obj['id'];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,36 +174,59 @@ class ActivityStreams {
|
||||
$this->saved_recips = $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get single property from Activity object
|
||||
*
|
||||
* @param string $property
|
||||
* @param mixed $default return value if property or object not set
|
||||
* or object is a string id which could not be fetched.
|
||||
* @return mixed
|
||||
*/
|
||||
public function objprop(string $property, mixed $default = false): mixed {
|
||||
$x = $this->get_property_obj($property, $this->obj);
|
||||
return (isset($x)) ? $x : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Collects all recipients.
|
||||
*
|
||||
* @param string $base
|
||||
* @param mixed $base
|
||||
* @param string $namespace (optional) default empty
|
||||
* @return array
|
||||
*/
|
||||
function collect_recips($base = '', $namespace = '') {
|
||||
$x = [];
|
||||
public function collect_recips(mixed $base = '', string $namespace = ''): array {
|
||||
$result = [];
|
||||
$tmp = [];
|
||||
|
||||
$fields = ['to', 'cc', 'bto', 'bcc', 'audience'];
|
||||
foreach ($fields as $f) {
|
||||
$y = $this->get_compound_property($f, $base, $namespace);
|
||||
if ($y) {
|
||||
if (!is_array($this->raw_recips)) {
|
||||
$this->raw_recips = [];
|
||||
}
|
||||
|
||||
if (!is_array($y)) {
|
||||
$y = [$y];
|
||||
}
|
||||
$this->raw_recips[$f] = $y;
|
||||
$x = array_merge($x, $y);
|
||||
foreach ($fields as $field) {
|
||||
// don't expand these yet
|
||||
$values = $this->get_property_obj($field, $base, $namespace);
|
||||
if ($values) {
|
||||
$values = force_array($values);
|
||||
$tmp[$field] = $values;
|
||||
$result = array_values(array_unique(array_merge($result, $values)));
|
||||
}
|
||||
// Merge the object recipients if they exist.
|
||||
$values = $this->objprop($field);
|
||||
if ($values) {
|
||||
$values = force_array($values);
|
||||
$tmp[$field] = ((isset($tmp[$field])) ? array_merge($tmp[$field], $values) : $values);
|
||||
$result = array_values(array_unique(array_merge($result, $values)));
|
||||
}
|
||||
// remove duplicates
|
||||
if (isset($tmp[$field])) {
|
||||
$tmp[$field] = array_values(array_unique($tmp[$field]));
|
||||
}
|
||||
}
|
||||
// not yet ready for prime time
|
||||
// $x = $this->expand($x,$base,$namespace);
|
||||
return $x;
|
||||
$this->raw_recips = $tmp;
|
||||
|
||||
// not yet ready for prime time
|
||||
// $result = $this->expand($result,$base,$namespace);
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
function expand($arr, $base = '', $namespace = '') {
|
||||
$ret = [];
|
||||
|
||||
@@ -274,12 +330,27 @@ class ActivityStreams {
|
||||
* @return NULL|mixed
|
||||
*/
|
||||
|
||||
function fetch_property($url) {
|
||||
return self::fetch($url);
|
||||
}
|
||||
function fetch_property($url, $channel = null) {
|
||||
$x = null;
|
||||
|
||||
static function fetch($url, $channel = null) {
|
||||
return Activity::fetch($url, $channel);
|
||||
if (str_starts_with($url, z_root() . '/item/')) {
|
||||
$x = Activity::fetch_local($url, $this->portable_id ?? '');
|
||||
logger('local: ' . print_r($x,true));
|
||||
}
|
||||
|
||||
if (!$x) {
|
||||
$x = Activity::fetch($url, $channel);
|
||||
if ($x === null && strpos($url, '/channel/')) {
|
||||
// look for other nomadic channels which might be alive
|
||||
$zf = Zotfinger::exec($url, $channel);
|
||||
if ($zf) {
|
||||
$url = $zf['signature']['signer'];
|
||||
$x = Activity::fetch($url, $channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
static function is_an_actor($s) {
|
||||
@@ -290,7 +361,7 @@ class ActivityStreams {
|
||||
if (!$s) {
|
||||
return false;
|
||||
}
|
||||
return (in_array($s, ['Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact']));
|
||||
return (in_array($s, ['Announce', 'Like', 'Dislike', 'Flag', 'Block', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact']));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,20 +375,25 @@ class ActivityStreams {
|
||||
|
||||
function get_actor($property, $base = '', $namespace = '') {
|
||||
$x = $this->get_property_obj($property, $base, $namespace);
|
||||
|
||||
if ($this->is_url($x)) {
|
||||
$y = Activity::get_cached_actor($x);
|
||||
$y = Activity::get_actor($x);
|
||||
if ($y) {
|
||||
return $y;
|
||||
}
|
||||
}
|
||||
|
||||
$actor = $this->get_compound_property($property, $base, $namespace, true);
|
||||
|
||||
if (is_array($actor) && self::is_an_actor($actor['type'])) {
|
||||
if (array_key_exists('id', $actor) && (!array_key_exists('inbox', $actor))) {
|
||||
$actor = $this->fetch_property($actor['id']);
|
||||
}
|
||||
return $actor;
|
||||
}
|
||||
return null;
|
||||
|
||||
return Activity::get_unknown_actor($this->data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -332,13 +408,26 @@ class ActivityStreams {
|
||||
*/
|
||||
function get_compound_property($property, $base = '', $namespace = '', $first = false) {
|
||||
$x = $this->get_property_obj($property, $base, $namespace);
|
||||
|
||||
if ($this->is_url($x)) {
|
||||
$y = $this->fetch_property($x);
|
||||
$cached = ASCache::Get($x);
|
||||
if ($cached) {
|
||||
// logger('AS cached: ' . $x);
|
||||
$y = unserialise($cached);
|
||||
}
|
||||
else {
|
||||
// logger('AS fetching: ' . $x);
|
||||
$y = $this->fetch_property($x);
|
||||
if ($y) {
|
||||
ASCache::Set($x, serialise($y));
|
||||
}
|
||||
}
|
||||
if (is_array($y)) {
|
||||
$x = $y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// verify and unpack JSalmon signature if present
|
||||
|
||||
if (is_array($x) && array_key_exists('signed', $x)) {
|
||||
@@ -438,4 +527,58 @@ class ActivityStreams {
|
||||
|
||||
}
|
||||
|
||||
public function checkEddsaSignature() {
|
||||
$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 (!$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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($publicKey) {
|
||||
$this->sigok = (new JcsEddsa2022)->verify($this->data, $publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once('include/plugin.php');
|
||||
require_once('include/channel.php');
|
||||
@@ -65,7 +66,7 @@ class Apps {
|
||||
}
|
||||
|
||||
static public function get_base_apps() {
|
||||
$x = get_config('system','base_apps',[
|
||||
$x = Config::Get('system','base_apps',[
|
||||
'Connections',
|
||||
'Contact Roles',
|
||||
'Network',
|
||||
@@ -159,7 +160,7 @@ class Apps {
|
||||
foreach(self::$available_apps as $iapp) {
|
||||
if($iapp['app_id'] == hash('whirlpool',$app['name'])) {
|
||||
$notfound = false;
|
||||
if(($iapp['app_version'] !== $app['version'])
|
||||
if((isset($app['version']) && $iapp['app_version'] !== $app['version'])
|
||||
|| ($app['plugin'] && (! $iapp['app_plugin']))) {
|
||||
return intval($iapp['app_id']);
|
||||
}
|
||||
@@ -236,6 +237,7 @@ class Apps {
|
||||
$ret['photo'] = $baseurl . '/' . get_default_profile_photo(80);
|
||||
|
||||
$ret['type'] = 'system';
|
||||
$ret['plugin'] = '';
|
||||
|
||||
foreach($ret as $k => $v) {
|
||||
if(strpos($v,'http') === 0) {
|
||||
@@ -300,7 +302,7 @@ class Apps {
|
||||
break;
|
||||
default:
|
||||
if($config)
|
||||
$unset = ((get_config('system', $require[0]) == $require[1]) ? false : true);
|
||||
$unset = ((Config::Get('system', $require[0]) == $require[1]) ? false : true);
|
||||
else
|
||||
$unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true);
|
||||
if($unset)
|
||||
@@ -351,8 +353,6 @@ class Apps {
|
||||
'Directory' => t('Directory'),
|
||||
'Help' => t('Help'),
|
||||
'Mail' => t('Mail'),
|
||||
'Mood' => t('Mood'),
|
||||
'Poke' => t('Poke'),
|
||||
'Chat' => t('Chat'),
|
||||
'Search' => t('Search'),
|
||||
'Probe' => t('Probe'),
|
||||
@@ -418,11 +418,28 @@ class Apps {
|
||||
static public function app_render($papp, $mode = 'view') {
|
||||
$installed = false;
|
||||
|
||||
if(! $papp)
|
||||
if(!$papp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(! $papp['photo'])
|
||||
/**
|
||||
* @hooks app_render_before
|
||||
* Hook to manipulate the papp array before rendering
|
||||
*/
|
||||
|
||||
$hookinfo = [
|
||||
'name' => $papp['name'],
|
||||
'photo' => $papp['photo']
|
||||
];
|
||||
|
||||
call_hooks('app_render_manipulate_photo', $hookinfo);
|
||||
|
||||
// We will only allow to manipulate the photo
|
||||
$papp['photo'] = $hookinfo['photo'];
|
||||
|
||||
if(!$papp['photo']) {
|
||||
$papp['photo'] = 'icon:gear';
|
||||
}
|
||||
|
||||
self::translate_system_apps($papp);
|
||||
|
||||
@@ -507,7 +524,7 @@ class Apps {
|
||||
break;
|
||||
default:
|
||||
if($config)
|
||||
$unset = ((get_config('system', $require[0]) === $require[1]) ? false : true);
|
||||
$unset = ((Config::Get('system', $require[0]) === $require[1]) ? false : true);
|
||||
else
|
||||
$unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true);
|
||||
if($unset)
|
||||
@@ -521,8 +538,13 @@ class Apps {
|
||||
$hosturl = '';
|
||||
|
||||
if(local_channel()) {
|
||||
if(self::app_installed(local_channel(),$papp) && !$papp['deleted'])
|
||||
if(self::app_installed(local_channel(),$papp)) {
|
||||
$installed = true;
|
||||
}
|
||||
|
||||
if ($installed && isset($papp['deleted']) && $papp['deleted']) {
|
||||
$installed = false;
|
||||
}
|
||||
|
||||
$hosturl = z_root() . '/';
|
||||
}
|
||||
@@ -595,12 +617,12 @@ class Apps {
|
||||
'$edit' => ((local_channel() && $installed && $mode == 'edit') ? t('Edit') : ''),
|
||||
'$delete' => ((local_channel() && $mode == 'edit') ? t('Delete') : ''),
|
||||
'$undelete' => ((local_channel() && $mode == 'edit') ? t('Undelete') : ''),
|
||||
'$settings_url' => ((local_channel() && $installed && $mode == 'list') ? $papp['settings_url'] : ''),
|
||||
'$deleted' => $papp['deleted'],
|
||||
'$settings_url' => ((local_channel() && $installed && $mode == 'list' && isset($papp['settings_url'])) ? $papp['settings_url'] : ''),
|
||||
'$deleted' => $papp['deleted'] ?? false,
|
||||
'$feature' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
|
||||
'$pin' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
|
||||
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
|
||||
'$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
|
||||
'$featured' => ((isset($papp['categories']) && strpos($papp['categories'], 'nav_featured_app') !== false) ? true : false),
|
||||
'$pinned' => ((isset($papp['categories']) && strpos($papp['categories'], 'nav_pinned_app') !== false) ? true : false),
|
||||
'$mode' => $mode,
|
||||
'$add' => t('Add to app-tray'),
|
||||
'$remove' => t('Remove from app-tray'),
|
||||
@@ -639,7 +661,7 @@ class Apps {
|
||||
);
|
||||
if($r) {
|
||||
if($app['uid']) {
|
||||
if($app['categories'] && (! $app['term'])) {
|
||||
if((isset($app['categories']) && $app['categories']) && !(isset($app['term']) && $app['term'])) {
|
||||
$r[0]['term'] = q("select * from term where otype = %d and oid = %d",
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($r[0]['id'])
|
||||
@@ -939,7 +961,7 @@ class Apps {
|
||||
|
||||
$conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order');
|
||||
|
||||
$x = (($uid) ? get_pconfig($uid,'system',$conf) : get_config('system',$conf));
|
||||
$x = (($uid) ? get_pconfig($uid,'system',$conf) : Config::Get('system',$conf));
|
||||
if(($x) && (! is_array($x))) {
|
||||
$y = explode(',',$x);
|
||||
$y = array_map('trim',$y);
|
||||
@@ -1184,7 +1206,7 @@ class Apps {
|
||||
$ret['success'] = true;
|
||||
$ret['app_id'] = $darray['app_id'];
|
||||
}
|
||||
if($arr['categories']) {
|
||||
if(isset($arr['categories']) && $arr['categories']) {
|
||||
$x = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
|
||||
dbesc($darray['app_id']),
|
||||
intval($darray['app_channel'])
|
||||
@@ -1282,7 +1304,7 @@ class Apps {
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($x[0]['id'])
|
||||
);
|
||||
if($arr['categories']) {
|
||||
if(isset($arr['categories']) && $arr['categories']) {
|
||||
$y = explode(',',$arr['categories']);
|
||||
if($y) {
|
||||
foreach($y as $t) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -2,53 +2,56 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
/**
|
||||
* cache api
|
||||
*/
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
/**
|
||||
* cache api
|
||||
*/
|
||||
class Cache {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns cached content
|
||||
*
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $age in SQL format, default is '30 DAY'
|
||||
* @return string
|
||||
*/
|
||||
|
||||
public static function get($key, $age = '') {
|
||||
|
||||
$hash = hash('whirlpool',$key);
|
||||
public static function get($key, $age = '') {
|
||||
// $hash = hash('whirlpool',$key);
|
||||
$hash = uuid_from_url($key);
|
||||
|
||||
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
|
||||
dbesc($hash),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(($age ? $age : get_config('system','object_cache_days', '30') . ' DAY'))
|
||||
db_quoteinterval(($age ? $age : Config::Get('system','object_cache_days', '30') . ' DAY'))
|
||||
);
|
||||
|
||||
|
||||
if ($r)
|
||||
return $r[0]['v'];
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static function set($key,$value) {
|
||||
// $hash = hash('whirlpool',$key);
|
||||
$hash = uuid_from_url($key);
|
||||
|
||||
$hash = hash('whirlpool',$key);
|
||||
|
||||
$r = q("SELECT * FROM cache WHERE k = '%s' limit 1",
|
||||
$r = q("SELECT * FROM cache WHERE k = '%s' LIMIT 1",
|
||||
dbesc($hash)
|
||||
);
|
||||
if($r) {
|
||||
q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'",
|
||||
dbesc($value),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($hash));
|
||||
dbesc($hash)
|
||||
);
|
||||
}
|
||||
else {
|
||||
q("INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')",
|
||||
q("INSERT INTO cache (k, v, updated) VALUES ('%s', '%s', '%s')",
|
||||
dbesc($hash),
|
||||
dbesc($value),
|
||||
dbesc(datetime_convert()));
|
||||
dbesc(datetime_convert())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
|
||||
class Config {
|
||||
|
||||
@@ -14,20 +15,41 @@ class Config {
|
||||
* @param string $family
|
||||
* The category of the configuration value
|
||||
*/
|
||||
static public function Load($family) {
|
||||
if(! array_key_exists($family, \App::$config))
|
||||
\App::$config[$family] = array();
|
||||
public static function Load($family, $recursionCounter = 0) {
|
||||
if (! array_key_exists($family, App::$config)) {
|
||||
App::$config[$family] = [];
|
||||
}
|
||||
|
||||
if(! array_key_exists('config_loaded', \App::$config[$family])) {
|
||||
// We typically continue when presented with minor DB issues,
|
||||
// but loading the site configuration is more important.
|
||||
|
||||
// Check for query returning false and give it approx 30 seconds
|
||||
// to recover if there's a problem. This is intended to fix a
|
||||
// rare issue on Galera where temporary sync issues were causing
|
||||
// the site encryption keys to be regenerated, which was causing
|
||||
// communication issues for members.
|
||||
|
||||
// This code probably belongs at the database layer, but we don't
|
||||
// necessarily want to shut the site down for problematic queries
|
||||
// caused by bad data. That could be used in a denial of service
|
||||
// attack. Those do need to be (and they are) logged.
|
||||
|
||||
if (! array_key_exists('config_loaded', App::$config[$family])) {
|
||||
$r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family));
|
||||
if($r !== false) {
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
$k = $rr['k'];
|
||||
\App::$config[$family][$k] = $rr['v'];
|
||||
}
|
||||
if ($r === false && !App::$install) {
|
||||
sleep(3);
|
||||
$recursionCounter ++;
|
||||
if ($recursionCounter > 10) {
|
||||
system_unavailable();
|
||||
}
|
||||
\App::$config[$family]['config_loaded'] = true;
|
||||
self::Load($family, $recursionCounter);
|
||||
}
|
||||
elseif (is_array($r)) {
|
||||
foreach ($r as $rr) {
|
||||
$k = $rr['k'];
|
||||
App::$config[$family][$k] = $rr['v'];
|
||||
}
|
||||
App::$config[$family]['config_loaded'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,19 +68,19 @@ class Config {
|
||||
* @return mixed
|
||||
* Return the set value, or false if the database update failed
|
||||
*/
|
||||
static public function Set($family, $key, $value) {
|
||||
public static function Set($family, $key, $value) {
|
||||
// manage array value
|
||||
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
|
||||
$dbvalue = ((is_array($value)) ? 'json:' . json_encode($value) : $value);
|
||||
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
|
||||
|
||||
if(self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) {
|
||||
if (self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) {
|
||||
$ret = q("INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ",
|
||||
dbesc($family),
|
||||
dbesc($key),
|
||||
dbesc($dbvalue)
|
||||
);
|
||||
if($ret) {
|
||||
\App::$config[$family][$key] = $value;
|
||||
if ($ret) {
|
||||
App::$config[$family][$key] = $value;
|
||||
$ret = $value;
|
||||
}
|
||||
return $ret;
|
||||
@@ -70,8 +92,8 @@ class Config {
|
||||
dbesc($key)
|
||||
);
|
||||
|
||||
if($ret) {
|
||||
\App::$config[$family][$key] = $value;
|
||||
if ($ret) {
|
||||
App::$config[$family][$key] = $value;
|
||||
$ret = $value;
|
||||
}
|
||||
|
||||
@@ -93,21 +115,37 @@ class Config {
|
||||
* The category of the configuration value
|
||||
* @param string $key
|
||||
* The configuration key to query
|
||||
* @param string $default (optional) default false
|
||||
* @param mixed $default (optional) default false
|
||||
* @return mixed Return value or false on error or if not set
|
||||
*/
|
||||
static public function Get($family, $key, $default = false) {
|
||||
if((! array_key_exists($family, \App::$config)) || (! array_key_exists('config_loaded', \App::$config[$family])))
|
||||
self::Load($family);
|
||||
public static function Get($family, $key, $default = false) {
|
||||
|
||||
if(array_key_exists('config_loaded', \App::$config[$family])) {
|
||||
if(! array_key_exists($key, \App::$config[$family])) {
|
||||
if ((! array_key_exists($family, App::$config)) || (! array_key_exists('config_loaded', App::$config[$family]))) {
|
||||
self::Load($family);
|
||||
}
|
||||
|
||||
if (array_key_exists('config_loaded', App::$config[$family])) {
|
||||
if (! array_key_exists($key, App::$config[$family])) {
|
||||
return $default;
|
||||
}
|
||||
return ((! is_array(\App::$config[$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$family][$key]))
|
||||
? unserialize(\App::$config[$family][$key])
|
||||
: \App::$config[$family][$key]
|
||||
);
|
||||
|
||||
$value = App::$config[$family][$key];
|
||||
|
||||
if (! is_array($value)) {
|
||||
if (substr($value, 0, 5) == 'json:') {
|
||||
return json_decode(substr($value, 5), true);
|
||||
} 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
|
||||
// compatibility. JSON serialization should be prefered.
|
||||
return unserialize($value, array('allowed_classes' => false));
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
@@ -125,12 +163,13 @@ class Config {
|
||||
* The configuration key to delete
|
||||
* @return mixed
|
||||
*/
|
||||
static public function Delete($family, $key) {
|
||||
public static function Delete($family, $key) {
|
||||
|
||||
$ret = false;
|
||||
|
||||
if(array_key_exists($family, \App::$config) && array_key_exists($key, \App::$config[$family]))
|
||||
unset(\App::$config[$family][$key]);
|
||||
if (array_key_exists($family, App::$config) && array_key_exists($key, App::$config[$family])) {
|
||||
unset(App::$config[$family][$key]);
|
||||
}
|
||||
|
||||
$ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'",
|
||||
dbesc($family),
|
||||
@@ -153,7 +192,7 @@ class Config {
|
||||
* The configuration key to query
|
||||
* @return mixed
|
||||
*/
|
||||
static private function get_from_storage($family,$key) {
|
||||
private static function get_from_storage($family, $key) {
|
||||
$ret = q("SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1",
|
||||
dbesc($family),
|
||||
dbesc($key)
|
||||
@@ -161,5 +200,4 @@ class Config {
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ namespace Zotlabs\Lib;
|
||||
use App;
|
||||
use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Daemon\Master;
|
||||
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Connect {
|
||||
|
||||
@@ -69,7 +68,8 @@ class Connect {
|
||||
$xchan_hash = '';
|
||||
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
|
||||
|
||||
$r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ",
|
||||
// We need both, the xchan and the hubloc here hence use JOIN instead of LEFT JOIN
|
||||
$r = q("SELECT * FROM xchan JOIN hubloc ON xchan_hash = hubloc_hash WHERE ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ORDER BY hubloc_id DESC",
|
||||
dbesc($url),
|
||||
dbesc($url),
|
||||
dbesc($url)
|
||||
@@ -80,12 +80,13 @@ class Connect {
|
||||
// reset results to the best record or the first if we don't have the best
|
||||
// note: this is a single record and not an array of results
|
||||
|
||||
$r = Libzot::zot_record_preferred($r,'xchan_network');
|
||||
$r = Libzot::zot_record_preferred($r, 'xchan_network');
|
||||
|
||||
}
|
||||
|
||||
$singleton = false;
|
||||
$d = false;
|
||||
$wf = false;
|
||||
|
||||
if (! $r) {
|
||||
|
||||
@@ -94,7 +95,7 @@ class Connect {
|
||||
$wf = discover_by_webbie($url,$protocol);
|
||||
|
||||
if (! $wf) {
|
||||
$feeds = get_config('system','feed_contacts');
|
||||
$feeds = Config::Get('system','feed_contacts');
|
||||
|
||||
if (($feeds) && (in_array($protocol, [ '', 'feed', 'rss' ]))) {
|
||||
$d = discover_by_url($url);
|
||||
@@ -108,10 +109,12 @@ class Connect {
|
||||
|
||||
if ($wf || $d) {
|
||||
|
||||
$xchan_hash = (($wf) ? $wf : $url);
|
||||
|
||||
// something was discovered - find the record which was just created.
|
||||
|
||||
$r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' ) $sql_options",
|
||||
dbesc(($wf) ? $wf : $url),
|
||||
dbesc($xchan_hash),
|
||||
dbesc($url),
|
||||
dbesc($url)
|
||||
);
|
||||
@@ -119,7 +122,7 @@ class Connect {
|
||||
// convert to a single record (once again preferring a zot solution in the case of multiples)
|
||||
|
||||
if ($r) {
|
||||
$r = Libzot::zot_record_preferred($r,'xchan_network');
|
||||
$r = Libzot::zot_record_preferred($r, 'xchan_network');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Exception;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Crypto {
|
||||
|
||||
@@ -44,7 +45,7 @@ class Crypto {
|
||||
'encrypt_key' => false
|
||||
];
|
||||
|
||||
$conf = get_config('system', 'openssl_conf_file');
|
||||
$conf = Config::Get('system', 'openssl_conf_file');
|
||||
|
||||
if ($conf) {
|
||||
$openssl_options['config'] = $conf;
|
||||
|
||||
@@ -1,21 +1,39 @@
|
||||
<?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 = '';
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
function __construct($db_revision) {
|
||||
|
||||
$this->config_name = 'db_version';
|
||||
$this->func_prefix = '_';
|
||||
|
||||
$build = get_config('system', 'db_version', 0);
|
||||
$build = Config::Get('system', 'db_version', 0);
|
||||
if(! intval($build))
|
||||
$build = set_config('system', 'db_version', $db_revision);
|
||||
$build = Config::Set('system', 'db_version', $db_revision);
|
||||
|
||||
if($build == $db_revision) {
|
||||
// Nothing to be done.
|
||||
@@ -27,7 +45,7 @@ class DB_Upgrade {
|
||||
logger('Critical: check_config unable to determine database schema version');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$current = intval($db_revision);
|
||||
|
||||
if($stored < $current) {
|
||||
@@ -38,7 +56,7 @@ class DB_Upgrade {
|
||||
for($x = $stored + 1; $x <= $current; $x ++) {
|
||||
$s = '_' . $x;
|
||||
$cls = '\\Zotlabs\Update\\' . $s ;
|
||||
if(! class_exists($cls)) {
|
||||
if(! class_exists($cls)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,10 +70,10 @@ class DB_Upgrade {
|
||||
|
||||
Config::Load('database');
|
||||
|
||||
if(get_config('database', $s))
|
||||
if(Config::Get('database', $s))
|
||||
break;
|
||||
set_config('database',$s, '1');
|
||||
|
||||
Config::Set('database',$s, '1');
|
||||
|
||||
|
||||
$c = new $cls();
|
||||
|
||||
@@ -65,10 +83,10 @@ class DB_Upgrade {
|
||||
|
||||
|
||||
$source = t('Source code of failed update: ') . "\n\n" . @file_get_contents('Zotlabs/Update/' . $s . '.php');
|
||||
|
||||
|
||||
|
||||
// Prevent sending hundreds of thousands of emails by creating
|
||||
// a lockfile.
|
||||
// a lockfile.
|
||||
|
||||
$lockfile = 'store/[data]/mailsent';
|
||||
|
||||
@@ -77,7 +95,7 @@ class DB_Upgrade {
|
||||
@unlink($lockfile);
|
||||
//send the administrator an e-mail
|
||||
file_put_contents($lockfile, $x);
|
||||
|
||||
|
||||
$r = q("select account_language from account where account_email = '%s' limit 1",
|
||||
dbesc(\App::$config['system']['admin_email'])
|
||||
);
|
||||
@@ -86,7 +104,7 @@ class DB_Upgrade {
|
||||
[
|
||||
'toEmail' => \App::$config['system']['admin_email'],
|
||||
'messageSubject' => sprintf( t('Update Error at %s'), z_root()),
|
||||
'textVersion' => replace_macros(get_intltext_template('update_fail_eml.tpl'),
|
||||
'textVersion' => replace_macros(get_intltext_template('update_fail_eml.tpl'),
|
||||
[
|
||||
'$sitename' => \App::$config['system']['sitename'],
|
||||
'$siteurl' => z_root(),
|
||||
@@ -104,11 +122,11 @@ class DB_Upgrade {
|
||||
pop_lang();
|
||||
}
|
||||
else {
|
||||
set_config('database',$s, 'success');
|
||||
Config::Set('database',$s, 'success');
|
||||
}
|
||||
}
|
||||
}
|
||||
set_config('system', 'db_version', $db_revision);
|
||||
Config::Set('system', 'db_version', $db_revision);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,33 @@
|
||||
<?php
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class DReport {
|
||||
|
||||
private $location;
|
||||
private $sender;
|
||||
private $recipient;
|
||||
private $name;
|
||||
private $message_id;
|
||||
private $message_uuid;
|
||||
private $status;
|
||||
private $date;
|
||||
|
||||
function __construct($location,$sender,$recipient,$message_id,$status = 'deliver') {
|
||||
$this->location = $location;
|
||||
$this->sender = $sender;
|
||||
$this->recipient = $recipient;
|
||||
$this->name = EMPTY_STR;
|
||||
$this->message_id = $message_id;
|
||||
$this->status = $status;
|
||||
$this->date = datetime_convert();
|
||||
function __construct($location, $sender, $recipient, $message_id, $message_uuid = '', $status = 'deliver') {
|
||||
$this->location = $location;
|
||||
$this->sender = $sender;
|
||||
$this->recipient = $recipient;
|
||||
$this->name = EMPTY_STR;
|
||||
$this->message_id = $message_id;
|
||||
$this->message_uuid = $message_uuid;
|
||||
$this->status = $status;
|
||||
$this->date = datetime_convert();
|
||||
}
|
||||
|
||||
function update($status) {
|
||||
$this->status = $status;
|
||||
$this->date = datetime_convert();
|
||||
$this->status = $status;
|
||||
$this->date = datetime_convert();
|
||||
}
|
||||
|
||||
function set_name($name) {
|
||||
@@ -35,24 +40,26 @@ class DReport {
|
||||
|
||||
|
||||
function set($arr) {
|
||||
$this->location = $arr['location'];
|
||||
$this->sender = $arr['sender'];
|
||||
$this->recipient = $arr['recipient'];
|
||||
$this->name = $arr['name'];
|
||||
$this->message_id = $arr['message_id'];
|
||||
$this->status = $arr['status'];
|
||||
$this->date = $arr['date'];
|
||||
$this->location = $arr['location'];
|
||||
$this->sender = $arr['sender'];
|
||||
$this->recipient = $arr['recipient'];
|
||||
$this->name = $arr['name'];
|
||||
$this->message_id = $arr['message_id'];
|
||||
$this->message_uuid = $arr['message_uuid'] ?? '';
|
||||
$this->status = $arr['status'];
|
||||
$this->date = $arr['date'];
|
||||
}
|
||||
|
||||
function get() {
|
||||
return array(
|
||||
'location' => $this->location,
|
||||
'sender' => $this->sender,
|
||||
'recipient' => $this->recipient,
|
||||
'name' => $this->name,
|
||||
'message_id' => $this->message_id,
|
||||
'status' => $this->status,
|
||||
'date' => $this->date
|
||||
'location' => $this->location,
|
||||
'sender' => $this->sender,
|
||||
'recipient' => $this->recipient,
|
||||
'name' => $this->name,
|
||||
'message_id' => $this->message_id,
|
||||
'message_uuid' => $this->message_uuid,
|
||||
'status' => $this->status,
|
||||
'date' => $this->date
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,7 +72,7 @@ class DReport {
|
||||
|
||||
static function is_storable($dr) {
|
||||
|
||||
if(get_config('system', 'disable_dreport'))
|
||||
if(Config::Get('system', 'disable_dreport'))
|
||||
return false;
|
||||
|
||||
/**
|
||||
@@ -94,19 +101,6 @@ class DReport {
|
||||
if(! $c)
|
||||
return false;
|
||||
|
||||
// legacy zot recipients add a space and their name to the xchan. remove it if true.
|
||||
|
||||
$legacy_recipient = strpos($dr['recipient'], ' ');
|
||||
if($legacy_recipient !== false) {
|
||||
$legacy_recipient_parts = explode(' ', $dr['recipient'], 2);
|
||||
$rxchan = $legacy_recipient_parts[0];
|
||||
}
|
||||
else {
|
||||
$rxchan = $dr['recipient'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// is the recipient one of our connections, or do we want to store every report?
|
||||
|
||||
$pcf = get_pconfig($c[0]['channel_id'],'system','dreport_store_all');
|
||||
@@ -117,7 +111,7 @@ class DReport {
|
||||
// So if a remote site says they can't find us, that's no big surprise
|
||||
// and just creates a lot of extra report noise
|
||||
|
||||
if(($dr['location'] !== z_root()) && ($dr['sender'] === $rxchan) && ($dr['status'] === 'recipient not found'))
|
||||
if(($dr['location'] !== z_root()) && ($dr['sender'] === $dr['recipient']) && ($dr['status'] === 'recipient not found'))
|
||||
return false;
|
||||
|
||||
// If you have a private post with a recipient list, every single site is going to report
|
||||
@@ -126,14 +120,14 @@ class DReport {
|
||||
// have a channel on that site.
|
||||
|
||||
$r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_url = '%s'",
|
||||
dbesc($rxchan),
|
||||
dbesc($dr['recipient']),
|
||||
dbesc($dr['location'])
|
||||
);
|
||||
if((! $r) && ($dr['status'] === 'recipient_not_found'))
|
||||
return false;
|
||||
|
||||
$r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
|
||||
dbesc($rxchan),
|
||||
dbesc($dr['recipient']),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
if($r)
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Zotlabs\Lib;
|
||||
* @brief File with functions and a class for generating system and email notifications.
|
||||
*/
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Enotify {
|
||||
|
||||
@@ -61,7 +62,7 @@ class Enotify {
|
||||
$product = t('$projectname'); // PLATFORM_NAME;
|
||||
$siteurl = z_root();
|
||||
$thanks = t('Thank You,');
|
||||
$sitename = get_config('system','sitename');
|
||||
$sitename = Config::Get('system','sitename');
|
||||
$site_admin = sprintf( t('%s Administrator'), $sitename);
|
||||
$opt_out1 = sprintf( t('This email was sent by %1$s at %2$s.'), t('$Projectname'), \App::get_hostname());
|
||||
$opt_out2 = sprintf( t('To stop receiving these messages, please adjust your Notification Settings at %s'), z_root() . '/settings');
|
||||
@@ -73,15 +74,15 @@ class Enotify {
|
||||
|
||||
// Do not translate 'noreply' as it must be a legal 7-bit email address
|
||||
|
||||
$reply_email = get_config('system', 'reply_address');
|
||||
$reply_email = Config::Get('system', 'reply_address');
|
||||
if(! $reply_email)
|
||||
$reply_email = 'noreply' . '@' . $hostname;
|
||||
|
||||
$sender_email = get_config('system', 'from_email');
|
||||
$sender_email = Config::Get('system', 'from_email');
|
||||
if(! $sender_email)
|
||||
$sender_email = 'Administrator' . '@' . $hostname;
|
||||
|
||||
$sender_name = get_config('system', 'from_email_name');
|
||||
$sender_name = Config::Get('system', 'from_email_name');
|
||||
if(! $sender_name)
|
||||
$sender_name = \Zotlabs\Lib\System::get_site_name();
|
||||
|
||||
@@ -122,8 +123,11 @@ class Enotify {
|
||||
// e.g. "your post", "David's photo", etc.
|
||||
$possess_desc = t('%s <!item_type!>');
|
||||
|
||||
$parent_mid = '';
|
||||
$parent_item = [];
|
||||
|
||||
// @@TODO: consider using switch instead of those elseif
|
||||
if ($params['type'] == NOTIFY_MAIL) {
|
||||
if (isset($params['type']) && $params['type'] == NOTIFY_MAIL) {
|
||||
logger('notification: mail');
|
||||
$subject = sprintf( t('[$Projectname:Notify] New direct message received at %s'), $sitename);
|
||||
|
||||
@@ -135,18 +139,18 @@ class Enotify {
|
||||
$itemlink = $siteurl . '/hq/' . gen_link_id($params['item']['mid']);
|
||||
}
|
||||
|
||||
elseif ($params['type'] === NOTIFY_COMMENT) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_COMMENT) {
|
||||
//logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
|
||||
|
||||
$moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false);
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
$action = t('commented on');
|
||||
$action = (($moderated) ? t('requested to comment on') : t('commented on'));
|
||||
|
||||
if(array_key_exists('item',$params)) {
|
||||
|
||||
if(in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
|
||||
if(in_array($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_SHARE])) {
|
||||
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
@@ -154,11 +158,14 @@ class Enotify {
|
||||
return;
|
||||
}
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_LIKE))
|
||||
$action = t('liked');
|
||||
if(activity_match($params['verb'], ['Like', ACTIVITY_LIKE]))
|
||||
$action = (($moderated) ? t('requested to like') : t('liked'));
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_DISLIKE))
|
||||
$action = t('disliked');
|
||||
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');
|
||||
|
||||
}
|
||||
|
||||
@@ -167,7 +174,7 @@ class Enotify {
|
||||
|
||||
}
|
||||
|
||||
$parent_mid = $params['parent_mid'];
|
||||
$parent_mid = $params['parent_mid'] ?? '';
|
||||
|
||||
// Check to see if there was already a notify for this post.
|
||||
// If so don't create a second notification
|
||||
@@ -251,20 +258,20 @@ class Enotify {
|
||||
|
||||
}
|
||||
|
||||
elseif ($params['type'] === NOTIFY_LIKE) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_LIKE) {
|
||||
// logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
if (array_key_exists('item',$params) && activity_match($params['item']['verb'],ACTIVITY_LIKE)) {
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]))) {
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$parent_mid = $params['parent_mid'];
|
||||
$parent_mid = $params['parent_mid'] ?? '';
|
||||
|
||||
// Check to see if there was already a notify for this post.
|
||||
// If so don't create a second notification
|
||||
@@ -291,22 +298,36 @@ class Enotify {
|
||||
);
|
||||
}
|
||||
|
||||
if (!$p) {
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
xchan_query($p);
|
||||
|
||||
//@@FIXME $p can be null (line 285)
|
||||
$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'));
|
||||
$moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false);
|
||||
|
||||
if(activity_match($params['item']['verb'], ['Like', ACTIVITY_LIKE]))
|
||||
$verb = (($moderated) ? t('requested to like') : t('liked'));
|
||||
|
||||
if(activity_match($params['item']['verb'], ['Dislike', ACTIVITY_DISLIKE]))
|
||||
$verb = (($moderated) ? t('requested to dislike') : t('disliked'));
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] === $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
$dest_str = sprintf(t('%1$s liked [zrl=%2$s]your %3$s[/zrl]'),
|
||||
$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);
|
||||
$item_post_type
|
||||
);
|
||||
else {
|
||||
pop_lang();
|
||||
return;
|
||||
@@ -328,7 +349,7 @@ class Enotify {
|
||||
|
||||
|
||||
|
||||
elseif($params['type'] === NOTIFY_WALL) {
|
||||
elseif(isset($params['type']) && $params['type'] === NOTIFY_WALL) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] %s posted to your profile wall') , $sender['xchan_name']);
|
||||
|
||||
$preamble = sprintf( t('%1$s posted to your profile wall at %2$s') , $sender['xchan_name'], $sitename);
|
||||
@@ -343,7 +364,7 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
elseif ($params['type'] === NOTIFY_TAGSELF) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_TAGSELF) {
|
||||
|
||||
$p = q("select id from notify where link = '%s' and uid = %d limit 1",
|
||||
dbesc($params['link']),
|
||||
@@ -367,7 +388,7 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
elseif ($params['type'] === NOTIFY_POKE) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_POKE) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] %1$s poked you') , $sender['xchan_name']);
|
||||
$preamble = sprintf( t('%1$s poked you at %2$s') , $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s [zrl=%2$s]poked you[/zrl].') ,
|
||||
@@ -384,7 +405,8 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
elseif ($params['type'] === NOTIFY_TAGSHARE) {
|
||||
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]') ,
|
||||
@@ -394,10 +416,9 @@ 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 ($params['type'] === NOTIFY_INTRO) {
|
||||
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);
|
||||
$epreamble = sprintf( t('You\'ve received [zrl=%1$s]a new connection request[/zrl] from %2$s.'),
|
||||
@@ -411,7 +432,8 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
elseif ($params['type'] === NOTIFY_SUGGEST) {
|
||||
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.'),
|
||||
@@ -426,14 +448,13 @@ 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 ($params['type'] === NOTIFY_CONFIRM) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_CONFIRM) {
|
||||
// ?
|
||||
}
|
||||
|
||||
elseif ($params['type'] === NOTIFY_SYSTEM) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_SYSTEM) {
|
||||
// ?
|
||||
}
|
||||
|
||||
@@ -466,6 +487,8 @@ class Enotify {
|
||||
|
||||
require_once('include/html2bbcode.php');
|
||||
|
||||
/*
|
||||
|
||||
do {
|
||||
$dups = false;
|
||||
$hash = random_string();
|
||||
@@ -474,10 +497,12 @@ class Enotify {
|
||||
if ($r)
|
||||
$dups = true;
|
||||
} while ($dups === true);
|
||||
*/
|
||||
|
||||
|
||||
|
||||
$datarray = [];
|
||||
$datarray['hash'] = $hash;
|
||||
$datarray['hash'] = $params['item']['uuid'] ?? new_uuid();
|
||||
$datarray['sender_hash'] = $sender['xchan_hash'];
|
||||
$datarray['xname'] = $sender['xchan_name'];
|
||||
$datarray['url'] = $sender['xchan_url'];
|
||||
@@ -488,12 +513,13 @@ class Enotify {
|
||||
$datarray['link'] = $itemlink;
|
||||
$datarray['parent'] = $parent_mid;
|
||||
$datarray['parent_item'] = $parent_item;
|
||||
$datarray['ntype'] = $params['type'];
|
||||
$datarray['verb'] = $params['verb'];
|
||||
$datarray['otype'] = $params['otype'];
|
||||
$datarray['ntype'] = $params['type'] ?? 0;
|
||||
$datarray['verb'] = $params['verb'] ?? '';
|
||||
$datarray['otype'] = $params['otype'] ?? '';
|
||||
$datarray['abort'] = false;
|
||||
$datarray['seen'] = 0;
|
||||
|
||||
$datarray['item'] = $params['item'];
|
||||
$datarray['item'] = $params['item'] ?? [];
|
||||
|
||||
call_hooks('enotify_store', $datarray);
|
||||
|
||||
@@ -504,7 +530,6 @@ class Enotify {
|
||||
|
||||
|
||||
// create notification entry in DB
|
||||
$seen = 0;
|
||||
|
||||
// Mark some notifications as seen right away
|
||||
// Note! The notification have to be created, because they are used to send emails
|
||||
@@ -514,7 +539,7 @@ class Enotify {
|
||||
|
||||
if (!$always_show_in_notices) {
|
||||
if (($params['type'] === NOTIFY_WALL) || ($params['type'] === NOTIFY_MAIL) || ($params['type'] === NOTIFY_INTRO)) {
|
||||
$seen = 1;
|
||||
$datarray['seen'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,14 +555,15 @@ class Enotify {
|
||||
intval($datarray['uid']),
|
||||
dbesc($datarray['link']),
|
||||
dbesc($datarray['parent']),
|
||||
intval($seen),
|
||||
intval($datarray['seen']),
|
||||
intval($datarray['ntype']),
|
||||
dbesc($datarray['verb']),
|
||||
dbesc($datarray['otype'])
|
||||
);
|
||||
|
||||
$r = q("select id from notify where hash = '%s' and uid = %d limit 1",
|
||||
dbesc($hash),
|
||||
$r = q("select id from notify where hash = '%s' and ntype = %d and uid = %d limit 1",
|
||||
dbesc($datarray['hash']),
|
||||
intval($datarray['ntype']),
|
||||
intval($recip['channel_id'])
|
||||
);
|
||||
if ($r) {
|
||||
@@ -569,7 +595,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');
|
||||
@@ -606,8 +632,8 @@ class Enotify {
|
||||
$datarray['preamble'] = $preamble;
|
||||
$datarray['sitename'] = $sitename;
|
||||
$datarray['siteurl'] = $siteurl;
|
||||
$datarray['type'] = $params['type'];
|
||||
$datarray['parent'] = $params['parent_mid'];
|
||||
$datarray['type'] = $params['type'] ?? '';
|
||||
$datarray['parent'] = $params['parent_mid'] ?? '';
|
||||
$datarray['source_name'] = $sender['xchan_name'];
|
||||
$datarray['source_link'] = $sender['xchan_url'];
|
||||
$datarray['source_photo'] = $sender['xchan_photo_s'];
|
||||
@@ -674,7 +700,6 @@ class Enotify {
|
||||
'$source_name' => $datarray['source_name'],
|
||||
'$source_link' => $datarray['source_link'],
|
||||
'$source_photo' => $datarray['source_photo'],
|
||||
'$username' => $datarray['to_name'],
|
||||
'$hsitelink' => $datarray['hsitelink'],
|
||||
'$hitemlink' => $datarray['hitemlink'],
|
||||
'$thanks' => $datarray['thanks'],
|
||||
@@ -696,7 +721,6 @@ class Enotify {
|
||||
'$source_name' => $datarray['source_name'],
|
||||
'$source_link' => $datarray['source_link'],
|
||||
'$source_photo' => $datarray['source_photo'],
|
||||
'$username' => $datarray['to_name'],
|
||||
'$tsitelink' => $datarray['tsitelink'],
|
||||
'$titemlink' => $datarray['titemlink'],
|
||||
'$thanks' => $datarray['thanks'],
|
||||
@@ -808,10 +832,10 @@ class Enotify {
|
||||
|
||||
localize_item($item);
|
||||
|
||||
if($item['shortlocalize']) {
|
||||
if(isset($item['shortlocalize'])) {
|
||||
$itemem_text = $item['shortlocalize'];
|
||||
}
|
||||
elseif($item['localize']) {
|
||||
elseif(isset($item['localize'])) {
|
||||
$itemem_text = $item['localize'];
|
||||
}
|
||||
else {
|
||||
@@ -820,10 +844,6 @@ class Enotify {
|
||||
: (($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]'))
|
||||
);
|
||||
|
||||
if($item['verb'] === ACTIVITY_SHARE) {
|
||||
$itemem_text = sprintf( t('repeated %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
|
||||
}
|
||||
|
||||
if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
|
||||
$itemem_text = t('shared a file with you');
|
||||
}
|
||||
@@ -844,27 +864,27 @@ class Enotify {
|
||||
|
||||
// convert this logic into a json array just like the system notifications
|
||||
|
||||
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
|
||||
$body = html2plain(bbcode($item['body'], ['drop_media']), 75, true);
|
||||
$body = html2plain(bbcode($item['body'], ['drop_media' => true, 'tryoembed' => false]), 75, true);
|
||||
if ($body) {
|
||||
$body = htmlentities($body, ENT_QUOTES, 'UTF-8', false);
|
||||
}
|
||||
|
||||
$x = array(
|
||||
'notify_link' => $item['llink'],
|
||||
'name' => $item[$who]['xchan_name'],
|
||||
'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']),
|
||||
'url' => $item[$who]['xchan_url'],
|
||||
'photo' => $item[$who]['xchan_photo_s'],
|
||||
'name' => $item['author']['xchan_name'],
|
||||
'addr' => $item['author']['xchan_addr'] ? $item['author']['xchan_addr'] : $item['author']['xchan_url'],
|
||||
'url' => $item['author']['xchan_url'],
|
||||
'photo' => $item['author']['xchan_photo_s'],
|
||||
'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['mid']) ? gen_link_id($item['mid']) : ''),
|
||||
'b64mid' => (($item['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)),
|
||||
'body' => $body,
|
||||
// these are for the superblock addon
|
||||
'hash' => $item[$who]['xchan_hash'],
|
||||
'hash' => $item['author']['xchan_hash'],
|
||||
'uid' => $item['uid'],
|
||||
'display' => true
|
||||
);
|
||||
@@ -884,9 +904,6 @@ class Enotify {
|
||||
if(strpos($message, $tt['xname']) === 0)
|
||||
$message = substr($message, strlen($tt['xname']) + 1);
|
||||
|
||||
$mid = basename($tt['link']);
|
||||
|
||||
$b64mid = gen_link_id($mid);
|
||||
$x = [
|
||||
'notify_link' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['link'] : z_root() . '/notify/view/' . $tt['id']),
|
||||
'name' => $tt['xname'],
|
||||
@@ -894,7 +911,7 @@ class Enotify {
|
||||
'photo' => $tt['photo'],
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(), $tt['created']),
|
||||
'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
|
||||
'b64mid' => (($tt['otype'] == 'item') ? $b64mid : ''),
|
||||
'b64mid' => (($tt['otype'] == 'item') ? $tt['hash'] : ''),
|
||||
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''),
|
||||
'message' => $message
|
||||
];
|
||||
|
||||
@@ -13,7 +13,7 @@ class IConfig {
|
||||
static public function Get(&$item, $family, $key, $default = false) {
|
||||
|
||||
$is_item = false;
|
||||
|
||||
|
||||
if(is_array($item)) {
|
||||
$is_item = true;
|
||||
if((! array_key_exists('iconfig',$item)) || (! is_array($item['iconfig'])))
|
||||
@@ -22,7 +22,7 @@ class IConfig {
|
||||
if(array_key_exists('item_id',$item))
|
||||
$iid = $item['item_id'];
|
||||
else
|
||||
$iid = $item['id'];
|
||||
$iid = $item['id'] ?? 0;
|
||||
}
|
||||
elseif(intval($item))
|
||||
$iid = $item;
|
||||
@@ -36,7 +36,7 @@ class IConfig {
|
||||
return $c['v'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$r = q("select * from iconfig where iid = %d and cat = '%s' and k = '%s' limit 1",
|
||||
intval($iid),
|
||||
dbesc($family),
|
||||
@@ -63,11 +63,11 @@ class IConfig {
|
||||
* $value - value of meta variable
|
||||
* $sharing - boolean (default false); if true the meta information is propagated with the item
|
||||
* to other sites/channels, mostly useful when $item is an array and has not yet been stored/delivered.
|
||||
* If the meta information is added after delivery and you wish it to be shared, it may be necessary to
|
||||
* alter the item edited timestamp and invoke the delivery process on the updated item. The edited
|
||||
* If the meta information is added after delivery and you wish it to be shared, it may be necessary to
|
||||
* alter the item edited timestamp and invoke the delivery process on the updated item. The edited
|
||||
* timestamp needs to be altered in order to trigger an item_store_update() at the receiving end.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static public function Set(&$item, $family, $key, $value, $sharing = false) {
|
||||
|
||||
@@ -162,4 +162,4 @@ class IConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class JSalmon {
|
||||
. base64url_encode($x['alg'],true);
|
||||
|
||||
$key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id']));
|
||||
logger('key: ' . print_r($key,true));
|
||||
logger('key: ' . print_r($key,true), LOGGER_DATA);
|
||||
if($key['portable_id'] && $key['public_key']) {
|
||||
if(Crypto::verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {
|
||||
logger('verified');
|
||||
|
||||
92
Zotlabs/Lib/JcsEddsa2022.php
Normal file
92
Zotlabs/Lib/JcsEddsa2022.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Mmccook\JsonCanonicalizator\JsonCanonicalizatorFactory;
|
||||
use StephenHill\Base58;
|
||||
|
||||
class JcsEddsa2022 {
|
||||
|
||||
public function __construct() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function sign($data, $channel): array {
|
||||
$base58 = new Base58();
|
||||
$pubkey = (new Multibase())->publicKey($channel['channel_epubkey']);
|
||||
$options = [
|
||||
'type' => 'DataIntegrityProof',
|
||||
'cryptosuite' => 'eddsa-jcs-2022',
|
||||
'created' => datetime_convert('UTC', 'UTC', 'now', ATOM_TIME),
|
||||
'verificationMethod' => channel_url($channel) . '#' . $pubkey,
|
||||
'proofPurpose' => 'assertionMethod',
|
||||
];
|
||||
|
||||
$optionsHash = $this->hash($this->signableOptions($options), true);
|
||||
$dataHash = $this->hash($this->signableData($data), true);
|
||||
|
||||
$options['proofValue'] = 'z' . $base58->encode(sodium_crypto_sign_detached($optionsHash . $dataHash,
|
||||
sodium_base642bin($channel['channel_eprvkey'], SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING)));
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function verify($data, $publicKey) {
|
||||
$base58 = new Base58();
|
||||
$encodedSignature = $data['proof']['proofValue'] ?? '';
|
||||
if (!str_starts_with($encodedSignature,'z')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$encodedSignature = substr($encodedSignature, 1);
|
||||
$optionsHash = $this->hash($this->signableOptions($data['proof']), true);
|
||||
$dataHash = $this->hash($this->signableData($data),true);
|
||||
|
||||
try {
|
||||
$result = sodium_crypto_sign_verify_detached($base58->decode($encodedSignature), $optionsHash . $dataHash,
|
||||
(new Multibase())->decode($publicKey, true));
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
logger('verify exception:' . $e->getMessage());
|
||||
}
|
||||
|
||||
logger('SignatureVerify (eddsa-jcs-2022) ' . (($result) ? 'true' : 'false'));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function signableData($data) {
|
||||
$signableData = [];
|
||||
if ($data) {
|
||||
foreach ($data as $k => $v) {
|
||||
if (!in_array($k, ['proof', 'signature'])) {
|
||||
$signableData[$k] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $signableData;
|
||||
}
|
||||
|
||||
public function signableOptions($options) {
|
||||
$signableOptions = [];
|
||||
|
||||
if ($options) {
|
||||
foreach ($options as $k => $v) {
|
||||
if ($k !== 'proofValue') {
|
||||
$signableOptions[$k] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $signableOptions;
|
||||
}
|
||||
|
||||
public function hash($obj, $binary = false) {
|
||||
return hash('sha256', $this->canonicalize($obj), $binary);
|
||||
}
|
||||
|
||||
public function canonicalize($data) {
|
||||
$canonicalization = JsonCanonicalizatorFactory::getInstance();
|
||||
return $canonicalization->canonicalize($data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
class Libsync {
|
||||
|
||||
@@ -135,14 +136,13 @@ class Libsync {
|
||||
$info['collection_members'] = $r;
|
||||
}
|
||||
|
||||
$interval = ((get_config('system', 'delivery_interval') !== false)
|
||||
? intval(get_config('system', 'delivery_interval')) : 2);
|
||||
$interval = Config::Get('queueworker', 'queue_interval', 500000);
|
||||
|
||||
logger('Packet: ' . print_r($info, true), LOGGER_DATA, LOG_DEBUG);
|
||||
|
||||
$total = count($synchubs);
|
||||
foreach ($synchubs as $hub) {
|
||||
$hash = random_string();
|
||||
$hash = new_uuid();
|
||||
$n = Libzot::build_packet($channel, 'sync', $env_recips, json_encode($info), 'hz', $hub['hubloc_sitekey'], $hub['site_crypto']);
|
||||
Queue::insert([
|
||||
'hash' => $hash,
|
||||
@@ -155,19 +155,26 @@ class Libsync {
|
||||
]);
|
||||
|
||||
|
||||
/*
|
||||
$x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
|
||||
if (intval($x[0]['total']) > intval(get_config('system', 'force_queue_threshold', 3000))) {
|
||||
|
||||
if (intval($x[0]['total']) > intval(Config::Get('system', 'force_queue_threshold', 3000))) {
|
||||
logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
|
||||
Queue::update($hash);
|
||||
continue;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
Master::Summon(['Deliver', $hash]);
|
||||
$total = $total - 1;
|
||||
|
||||
if ($interval && $total)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
/*
|
||||
$total = $total - 1;
|
||||
*/
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +199,10 @@ class Libsync {
|
||||
dbesc($sender)
|
||||
);
|
||||
|
||||
$DR = new DReport(z_root(), $sender, $d, 'sync');
|
||||
$mid = 'sync';
|
||||
|
||||
|
||||
$DR = new DReport(z_root(), $sender, $d, $mid);
|
||||
|
||||
if (!$r) {
|
||||
$DR->update('recipient not found');
|
||||
@@ -202,6 +212,7 @@ class Libsync {
|
||||
|
||||
$channel = $r[0];
|
||||
|
||||
|
||||
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
|
||||
|
||||
$max_friends = service_class_fetch($channel['channel_id'], 'total_channels');
|
||||
@@ -256,7 +267,7 @@ class Libsync {
|
||||
}
|
||||
|
||||
if ($cat !== 'hz_delpconfig') {
|
||||
set_pconfig($channel['channel_id'],$cat,$k,$v,$pconfig_updated[$k]);
|
||||
set_pconfig($channel['channel_id'], $cat, $k, $v, $pconfig_updated[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,8 +304,10 @@ class Libsync {
|
||||
if (array_key_exists('event_item', $arr) && $arr['event_item'])
|
||||
sync_items($channel, $arr['event_item'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null));
|
||||
|
||||
if (array_key_exists('item', $arr) && $arr['item'])
|
||||
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
|
||||
@@ -313,10 +326,7 @@ class Libsync {
|
||||
|
||||
if (array_key_exists('channel', $arr) && is_array($arr['channel']) && count($arr['channel'])) {
|
||||
|
||||
$remote_channel = $arr['channel'];
|
||||
$remote_channel['channel_id'] = $channel['channel_id'];
|
||||
|
||||
if (array_key_exists('channel_pageflags', $arr['channel']) && intval($arr['channel']['channel_pageflags'])) {
|
||||
if (array_key_exists('channel_pageflags', $arr['channel'])) {
|
||||
|
||||
// Several pageflags are site-specific and cannot be sync'd.
|
||||
// Only allow those bits which are shareable from the remote and then
|
||||
@@ -327,6 +337,8 @@ class Libsync {
|
||||
|
||||
}
|
||||
|
||||
$columns = db_columns('channel');
|
||||
|
||||
$disallowed = [
|
||||
'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey',
|
||||
'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted',
|
||||
@@ -337,16 +349,21 @@ class Libsync {
|
||||
'channel_a_delegate'
|
||||
];
|
||||
|
||||
$clean = [];
|
||||
foreach ($arr['channel'] as $k => $v) {
|
||||
if (in_array($k, $disallowed))
|
||||
continue;
|
||||
$clean[$k] = $v;
|
||||
if (empty($channel['channel_epubkey']) && empty($channel['channel_eprvkey'])) {
|
||||
$eckey = sodium_crypto_sign_keypair();
|
||||
$channel['channel_epubkey'] = sodium_bin2base64(sodium_crypto_sign_publickey($eckey), SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
|
||||
$channel['channel_eprvkey'] = sodium_bin2base64(sodium_crypto_sign_secretkey($eckey), SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
|
||||
}
|
||||
if (count($clean)) {
|
||||
foreach ($clean as $k => $v) {
|
||||
dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) . "' where channel_id = " . intval($channel['channel_id']));
|
||||
|
||||
foreach ($arr['channel'] as $k => $v) {
|
||||
if (in_array($k, $disallowed)) {
|
||||
continue;
|
||||
}
|
||||
if (!in_array($k, $columns)) {
|
||||
continue;
|
||||
}
|
||||
$r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v)
|
||||
. "' where channel_id = " . intval($channel['channel_id']));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,13 +757,12 @@ class Libsync {
|
||||
*/
|
||||
call_hooks('process_channel_sync_delivery', $addon);
|
||||
|
||||
$DR = new DReport(z_root(), $d, $d, 'sync', 'channel sync delivered');
|
||||
$DR = new DReport(z_root(), $d, $d, $mid, 'channel sync processed');
|
||||
|
||||
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
|
||||
|
||||
$result[] = $DR->get();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -755,13 +771,19 @@ class Libsync {
|
||||
*
|
||||
* @param array $sender
|
||||
* @param array $arr
|
||||
* @param boolean $absolute (optional) default false
|
||||
* @return array
|
||||
*/
|
||||
|
||||
static function sync_locations($sender, $arr, $absolute = false) {
|
||||
static function sync_locations($sender, $arr) {
|
||||
|
||||
$ret = [];
|
||||
$ret = [
|
||||
'change_message' => '',
|
||||
'changed' => false,
|
||||
'message' => ''
|
||||
];
|
||||
|
||||
$what = '';
|
||||
$changed = false;
|
||||
|
||||
// If a sender reports that the channel has been deleted, delete its hubloc
|
||||
if (isset($arr['deleted_locally']) && intval($arr['deleted_locally'])) {
|
||||
@@ -772,12 +794,9 @@ class Libsync {
|
||||
);
|
||||
}
|
||||
|
||||
if ($arr['locations']) {
|
||||
if (isset($arr['locations']) && $arr['locations']) {
|
||||
|
||||
if ($absolute)
|
||||
Libzot::check_location_move($sender['hash'], $arr['locations']);
|
||||
|
||||
$xisting = q("select * from hubloc where hubloc_hash = '%s'",
|
||||
$xisting = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0",
|
||||
dbesc($sender['hash'])
|
||||
);
|
||||
|
||||
@@ -849,7 +868,9 @@ class Libsync {
|
||||
);
|
||||
}
|
||||
|
||||
// update connection timestamp if this is the site we're talking to
|
||||
// Update connection timestamp if this is the site we're talking to.
|
||||
// Also mark all entries from the current site with different sitekeys
|
||||
// deleted (the site has been re-installed)
|
||||
// This only happens when called from import_xchan
|
||||
|
||||
$current_site = false;
|
||||
@@ -863,6 +884,12 @@ class Libsync {
|
||||
intval($r[0]['hubloc_id']),
|
||||
dbesc($t)
|
||||
);
|
||||
|
||||
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'])
|
||||
);
|
||||
|
||||
$current_site = true;
|
||||
}
|
||||
|
||||
@@ -912,14 +939,7 @@ class Libsync {
|
||||
$what .= 'primary_hub ';
|
||||
$changed = true;
|
||||
}
|
||||
elseif ($absolute) {
|
||||
// Absolute sync - make sure the current primary is correctly reflected in the xchan
|
||||
$pr = hubloc_change_primary($r[0]);
|
||||
if ($pr) {
|
||||
$what .= 'xchan_primary ';
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (intval($r[0]['hubloc_deleted']) && (!intval($location['deleted']))) {
|
||||
q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
@@ -988,9 +1008,9 @@ class Libsync {
|
||||
}
|
||||
}
|
||||
|
||||
// get rid of any hubs we have for this channel which weren't reported.
|
||||
// get rid of any hublocs we have for this channel which weren't reported.
|
||||
|
||||
if ($absolute && $xisting) {
|
||||
if ($xisting) {
|
||||
foreach ($xisting as $x) {
|
||||
if (!array_key_exists('updated', $x)) {
|
||||
logger('Deleting unreferenced hub location ' . $x['hubloc_addr']);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
use Zotlabs\Lib\Webfinger;
|
||||
@@ -20,7 +21,7 @@ class Libzotdir {
|
||||
|
||||
static function find_upstream_directory($dirmode) {
|
||||
|
||||
$preferred = get_config('system','directory_server');
|
||||
$preferred = Config::Get('system','directory_server');
|
||||
|
||||
// Thwart attempts to use a private directory
|
||||
|
||||
@@ -47,17 +48,17 @@ class Libzotdir {
|
||||
|
||||
$directory_fallback_servers = get_directory_fallback_servers();
|
||||
|
||||
$dirmode = intval(get_config('system','directory_mode'));
|
||||
$dirmode = intval(Config::Get('system','directory_mode'));
|
||||
if ($dirmode == DIRECTORY_MODE_NORMAL) {
|
||||
$toss = mt_rand(0,count($directory_fallback_servers));
|
||||
$preferred = $directory_fallback_servers[$toss];
|
||||
if(! $preferred) {
|
||||
$preferred = DIRECTORY_FALLBACK_MASTER;
|
||||
}
|
||||
set_config('system','directory_server',$preferred);
|
||||
Config::Set('system','directory_server',$preferred);
|
||||
}
|
||||
else {
|
||||
set_config('system','directory_server',z_root());
|
||||
Config::Set('system','directory_server',z_root());
|
||||
}
|
||||
}
|
||||
if($preferred) {
|
||||
@@ -77,7 +78,7 @@ class Libzotdir {
|
||||
|
||||
static function check_upstream_directory() {
|
||||
|
||||
$directory = get_config('system', 'directory_server');
|
||||
$directory = Config::Get('system', 'directory_server');
|
||||
|
||||
// it's possible there is no directory server configured and the local hub is being used.
|
||||
// If so, default to preserving the absence of a specific server setting.
|
||||
@@ -94,7 +95,7 @@ class Libzotdir {
|
||||
}
|
||||
|
||||
if (! $isadir)
|
||||
set_config('system', 'directory_server', '');
|
||||
Config::Set('system', 'directory_server', '');
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +107,7 @@ class Libzotdir {
|
||||
$ret = ((array_key_exists($setting,$_SESSION)) ? intval($_SESSION[$setting]) : false);
|
||||
|
||||
if($ret === false)
|
||||
$ret = get_config('directory', $setting);
|
||||
$ret = Config::Get('directory', $setting);
|
||||
|
||||
|
||||
// 'safemode' is the default if there is no observer or no established preference.
|
||||
@@ -114,7 +115,7 @@ class Libzotdir {
|
||||
if($setting === 'safemode' && $ret === false)
|
||||
$ret = 1;
|
||||
|
||||
if($setting === 'globaldir' && intval(get_config('system','localdir_hide')))
|
||||
if($setting === 'globaldir' && intval(Config::Get('system','localdir_hide')))
|
||||
$ret = 1;
|
||||
|
||||
return $ret;
|
||||
@@ -133,7 +134,7 @@ class Libzotdir {
|
||||
$globaldir = self::get_directory_setting($observer, 'globaldir');
|
||||
$pubforums = self::get_directory_setting($observer, 'pubforums');
|
||||
|
||||
$hide_local = intval(get_config('system','localdir_hide'));
|
||||
$hide_local = intval(Config::Get('system','localdir_hide'));
|
||||
if($hide_local)
|
||||
$globaldir = 1;
|
||||
|
||||
@@ -141,12 +142,12 @@ class Libzotdir {
|
||||
// Build urls without order and pubforums so it's easy to tack on the changed value
|
||||
// Probably there's an easier way to do this
|
||||
|
||||
$directory_sort_order = get_config('system','directory_sort_order');
|
||||
$directory_sort_order = Config::Get('system','directory_sort_order');
|
||||
if(! $directory_sort_order)
|
||||
$directory_sort_order = 'date';
|
||||
|
||||
$current_order = (($_REQUEST['order']) ? $_REQUEST['order'] : $directory_sort_order);
|
||||
$suggest = (($_REQUEST['suggest']) ? '&suggest=' . $_REQUEST['suggest'] : '');
|
||||
$current_order = $_REQUEST['order'] ?? $directory_sort_order;
|
||||
$suggest = ((isset($_REQUEST['suggest'])) ? '&suggest=' . $_REQUEST['suggest'] : '');
|
||||
|
||||
$url = 'directory?f=';
|
||||
|
||||
@@ -172,13 +173,12 @@ class Libzotdir {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the directory mode of this hub.
|
||||
* @brief fetches updates from known directories
|
||||
*
|
||||
* Checks the directory mode of this hub to see if it is some form of directory server. If it is,
|
||||
* get the directory realm of this hub. Fetch a list of all other directory servers in this realm and request
|
||||
* a directory sync packet. This will contain both directory updates and new ratings. Store these all in the DB.
|
||||
* In the case of updates, we will query each of them asynchronously from a poller task. Ratings are stored
|
||||
* directly if the rater's signature matches.
|
||||
* a directory sync packet. Store these all in the DB.
|
||||
* In the case of updates, we will query each of them asynchronously from a poller task.
|
||||
*
|
||||
* @param int $dirmode;
|
||||
*/
|
||||
@@ -233,6 +233,8 @@ class Libzotdir {
|
||||
if (! $r)
|
||||
return;
|
||||
|
||||
$dir_trusted_hosts = array_merge(get_directory_fallback_servers(), Config::Get('system', 'trusted_directory_servers', []));
|
||||
|
||||
foreach ($r as $rr) {
|
||||
if (! $rr['site_directory'])
|
||||
continue;
|
||||
@@ -243,7 +245,7 @@ class Libzotdir {
|
||||
// It will take about a month for a new directory to obtain the full current repertoire of channels.
|
||||
/** @FIXME Go back and pick up earlier ratings if this is a new directory server. These do not get refreshed. */
|
||||
|
||||
$token = get_config('system','realm_token');
|
||||
$token = Config::Get('system','realm_token');
|
||||
|
||||
$syncdate = (($rr['site_sync'] <= 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 : ''));
|
||||
@@ -264,31 +266,65 @@ class Libzotdir {
|
||||
|
||||
if (is_array($j['transactions']) && count($j['transactions'])) {
|
||||
foreach ($j['transactions'] as $t) {
|
||||
|
||||
if (empty($t['hash']) || empty($t['transaction_id']) || empty($t['address'])) {
|
||||
if (empty($t['hash']) || empty($t['host']) || empty($t['address'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$r = q("select * from updates where ud_guid = '%s' limit 1",
|
||||
dbesc($t['transaction_id'])
|
||||
$r = q("select * from updates where ud_hash = '%s' limit 1",
|
||||
dbesc($t['hash'])
|
||||
);
|
||||
if($r)
|
||||
continue;
|
||||
|
||||
$ud_flags = 0;
|
||||
if (is_array($t['flags']) && in_array('deleted',$t['flags']))
|
||||
$ud_flags |= UPDATE_FLAGS_DELETED;
|
||||
if (is_array($t['flags']) && in_array('forced',$t['flags']))
|
||||
$ud_flags |= UPDATE_FLAGS_FORCED;
|
||||
if ($r) {
|
||||
$update = 0;
|
||||
|
||||
$z = q("insert into updates ( ud_hash, ud_guid, ud_date, ud_flags, ud_addr )
|
||||
values ( '%s', '%s', '%s', %d, '%s' ) ",
|
||||
dbesc($t['hash']),
|
||||
dbesc($t['transaction_id']),
|
||||
dbesc($t['timestamp']),
|
||||
intval($ud_flags),
|
||||
dbesc($t['address'])
|
||||
);
|
||||
// no need to look at updates that originated from our own site
|
||||
if ($t['host'] === z_root()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// there is more recent xchan information
|
||||
if ($r[0]['ud_date'] <= $t['timestamp']) {
|
||||
$update = 1;
|
||||
}
|
||||
|
||||
// the host is trusted and flags have changed - update flags immediately
|
||||
if (in_array($t['host'], $dir_trusted_hosts) &&
|
||||
$rr['site_url'] === $t['host'] &&
|
||||
intval($r[0]['ud_flags']) !== intval($t['flags'])) {
|
||||
|
||||
q("UPDATE updates SET ud_update = %d, ud_flags = %d WHERE ud_id = %d",
|
||||
intval($update),
|
||||
intval($t['flags']),
|
||||
dbesc($r[0]['ud_id'])
|
||||
);
|
||||
|
||||
q("UPDATE xchan SET xchan_censored = %d WHERE xchan_hash = '%s'",
|
||||
intval($t['flags']),
|
||||
dbesc($r[0]['ud_hash'])
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$update) {
|
||||
continue;
|
||||
}
|
||||
|
||||
q("UPDATE updates SET ud_update = %d WHERE ud_id = %d",
|
||||
intval($update),
|
||||
dbesc($r[0]['ud_id'])
|
||||
);
|
||||
}
|
||||
else {
|
||||
q("insert into updates ( ud_hash, ud_host, ud_date, ud_addr, ud_update, ud_flags )
|
||||
values ( '%s', '%s', '%s', '%s', 1, %d) ",
|
||||
dbesc($t['hash']),
|
||||
dbesc($t['host']),
|
||||
dbesc($t['timestamp']),
|
||||
dbesc($t['address']),
|
||||
dbesc(in_array($t['host'], $dir_trusted_hosts) ? $t['flags'] : 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,8 +339,9 @@ class Libzotdir {
|
||||
*
|
||||
* Ignore updating records marked as deleted.
|
||||
*
|
||||
* If successful, sets ud_last in the DB to the current datetime for this
|
||||
* If successful, sets ud_updated in the DB to the current datetime for this
|
||||
* reddress/webbie.
|
||||
* Else update ud_last so we can stop trying after 7 days (Daemon/Poller.php)
|
||||
*
|
||||
* @param array $ud Entry from update table
|
||||
*/
|
||||
@@ -313,32 +350,44 @@ class Libzotdir {
|
||||
|
||||
logger('update_directory_entry: ' . print_r($ud,true), LOGGER_DATA);
|
||||
|
||||
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
|
||||
$success = false;
|
||||
$zf = [];
|
||||
// TODO: remove this check after all directory servers have version > 8.4
|
||||
// ud_addr will always be the channel url at that time
|
||||
$href = ((strpos($ud['ud_addr'], '://') === false) ? Webfinger::zot_url(punify($ud['ud_addr'])) : punify($ud['ud_addr']));
|
||||
if($href) {
|
||||
$zf = Zotfinger::exec($href);
|
||||
if($zf && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
|
||||
$xc = Libzot::import_xchan($zf['data']);
|
||||
|
||||
// xchan_hash mismatch - this can happen after a site re-install at the same url
|
||||
if ($xc['success'] && $xc['hash'] !== $ud['ud_hash']) {
|
||||
self::delete_by_hash($ud['ud_hash']);
|
||||
}
|
||||
|
||||
// if the channel was deleted - delete the entry in updates
|
||||
if (!empty($zf['data']['deleted_locally'])) {
|
||||
self::delete_by_hash($ud['ud_hash']);
|
||||
}
|
||||
|
||||
$href = Webfinger::zot_url(punify($ud['ud_addr']));
|
||||
if($href) {
|
||||
$zf = Zotfinger::exec($href);
|
||||
}
|
||||
if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
|
||||
$xc = Libzot::import_xchan($zf['data'], 0, $ud);
|
||||
// This is a workaround for a missing xchan_updated column
|
||||
// TODO: implement xchan_updated in the xchan table and update this column instead
|
||||
if($zf['data']['primary_location']['address'] && $zf['data']['primary_location']['url']) {
|
||||
if(!empty($zf['data']['primary_location']['url'])) {
|
||||
q("UPDATE hubloc SET hubloc_updated = '%s' WHERE hubloc_id_url = '%s' AND hubloc_primary = 1",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($zf['data']['primary_location']['url'])
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
q("update updates set ud_last = '%s' where ud_addr = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($ud['ud_addr'])
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
q("UPDATE updates SET ud_addr = '%s', ud_last = '%s' WHERE ud_hash = '%s'",
|
||||
dbesc($href ? $href : $ud['ud_addr']),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($ud['ud_hash'])
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -353,85 +402,78 @@ class Libzotdir {
|
||||
*/
|
||||
|
||||
static function local_dir_update($uid, $force) {
|
||||
logger('local_dir_update uid: ' . $uid, LOGGER_DEBUG);
|
||||
|
||||
|
||||
logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG);
|
||||
|
||||
$p = q("select channel.channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1",
|
||||
$p = q("select channel.channel_hash, channel_address, channel_timezone, profile.*, xchan.xchan_hidden, xchan.xchan_url from profile left join channel on channel_id = uid left join xchan on channel_hash = xchan_hash where profile.uid = %d and profile.is_default = 1",
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
$profile = array();
|
||||
$profile['encoding'] = 'zot';
|
||||
|
||||
if ($p) {
|
||||
$hash = $p[0]['channel_hash'];
|
||||
|
||||
$profile['description'] = $p[0]['pdesc'];
|
||||
$profile['birthday'] = $p[0]['dob'];
|
||||
if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],''))
|
||||
$profile['age'] = $age;
|
||||
|
||||
$profile['gender'] = $p[0]['gender'];
|
||||
$profile['marital'] = $p[0]['marital'];
|
||||
$profile['sexual'] = $p[0]['sexual'];
|
||||
$profile['locale'] = $p[0]['locality'];
|
||||
$profile['region'] = $p[0]['region'];
|
||||
$profile['postcode'] = $p[0]['postal_code'];
|
||||
$profile['country'] = $p[0]['country_name'];
|
||||
$profile['about'] = $p[0]['about'];
|
||||
$profile['homepage'] = $p[0]['homepage'];
|
||||
$profile['hometown'] = $p[0]['hometown'];
|
||||
|
||||
if ($p[0]['keywords']) {
|
||||
$tags = array();
|
||||
$k = explode(' ', $p[0]['keywords']);
|
||||
if ($k)
|
||||
foreach ($k as $kk)
|
||||
if (trim($kk))
|
||||
$tags[] = trim($kk);
|
||||
|
||||
if ($tags)
|
||||
$profile['keywords'] = $tags;
|
||||
}
|
||||
|
||||
$hidden = (1 - intval($p[0]['publish']));
|
||||
|
||||
logger('hidden: ' . $hidden);
|
||||
|
||||
$r = q("select xchan_hidden from xchan where xchan_hash = '%s'",
|
||||
dbesc($p[0]['channel_hash'])
|
||||
);
|
||||
|
||||
if(intval($r[0]['xchan_hidden']) != $hidden) {
|
||||
$r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'",
|
||||
intval($hidden),
|
||||
dbesc($hash)
|
||||
);
|
||||
}
|
||||
|
||||
$arr = [ 'channel_id' => $uid, 'hash' => $hash, 'profile' => $profile ];
|
||||
call_hooks('local_dir_update', $arr);
|
||||
|
||||
$address = channel_reddress($p[0]);
|
||||
|
||||
if (perm_is_allowed($uid, '', 'view_profile')) {
|
||||
self::import_directory_profile($hash, $arr['profile'], $address, 0);
|
||||
}
|
||||
else {
|
||||
// they may have made it private
|
||||
q("delete from xprof where xprof_hash = '%s'",
|
||||
dbesc($hash)
|
||||
);
|
||||
q("delete from xtag where xtag_hash = '%s'",
|
||||
dbesc($hash)
|
||||
);
|
||||
}
|
||||
|
||||
if (!$p) {
|
||||
logger('profile not found');
|
||||
return;
|
||||
}
|
||||
|
||||
$ud_hash = random_string() . '@' . \App::get_hostname();
|
||||
self::update_modtime($hash, $ud_hash, channel_reddress($p[0]),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
|
||||
$profile = [];
|
||||
$profile['encoding'] = 'zot';
|
||||
|
||||
$hash = $p[0]['channel_hash'];
|
||||
|
||||
$profile['description'] = $p[0]['pdesc'];
|
||||
$profile['birthday'] = $p[0]['dob'];
|
||||
if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],''))
|
||||
$profile['age'] = $age;
|
||||
|
||||
$profile['gender'] = $p[0]['gender'];
|
||||
$profile['marital'] = $p[0]['marital'];
|
||||
$profile['sexual'] = $p[0]['sexual'];
|
||||
$profile['locale'] = $p[0]['locality'];
|
||||
$profile['region'] = $p[0]['region'];
|
||||
$profile['postcode'] = $p[0]['postal_code'];
|
||||
$profile['country'] = $p[0]['country_name'];
|
||||
$profile['about'] = $p[0]['about'];
|
||||
$profile['homepage'] = $p[0]['homepage'];
|
||||
$profile['hometown'] = $p[0]['hometown'];
|
||||
|
||||
if ($p[0]['keywords']) {
|
||||
$tags = array();
|
||||
$k = explode(' ', $p[0]['keywords']);
|
||||
if ($k)
|
||||
foreach ($k as $kk)
|
||||
if (trim($kk))
|
||||
$tags[] = trim($kk);
|
||||
|
||||
if ($tags)
|
||||
$profile['keywords'] = $tags;
|
||||
}
|
||||
|
||||
$hidden = (1 - intval($p[0]['publish']));
|
||||
|
||||
logger('hidden: ' . $hidden);
|
||||
|
||||
if(intval($p[0]['xchan_hidden']) !== $hidden) {
|
||||
q("update xchan set xchan_hidden = %d where xchan_hash = '%s'",
|
||||
intval($hidden),
|
||||
dbesc($hash)
|
||||
);
|
||||
}
|
||||
|
||||
$arr = [ 'channel_id' => $uid, 'hash' => $hash, 'profile' => $profile ];
|
||||
call_hooks('local_dir_update', $arr);
|
||||
|
||||
if (perm_is_allowed($uid, '', 'view_profile')) {
|
||||
self::import_directory_profile($hash, $arr['profile']);
|
||||
}
|
||||
else {
|
||||
// they may have made it private
|
||||
q("delete from xprof where xprof_hash = '%s'",
|
||||
dbesc($hash)
|
||||
);
|
||||
q("delete from xtag where xtag_hash = '%s'",
|
||||
dbesc($hash)
|
||||
);
|
||||
}
|
||||
|
||||
self::update($hash, $p[0]['xchan_url']);
|
||||
}
|
||||
|
||||
|
||||
@@ -441,39 +483,48 @@ class Libzotdir {
|
||||
*
|
||||
* @param string $hash
|
||||
* @param array $profile
|
||||
* @param string $addr
|
||||
* @param number $ud_flags (optional) UPDATE_FLAGS_UPDATED
|
||||
* @param number $suppress_update (optional) default 0
|
||||
* @return boolean $updated if something changed
|
||||
*/
|
||||
|
||||
static function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) {
|
||||
static function import_directory_profile($hash, $profile) {
|
||||
|
||||
logger('import_directory_profile', LOGGER_DEBUG);
|
||||
if (! $hash)
|
||||
return false;
|
||||
|
||||
$arr = array();
|
||||
$arr = [];
|
||||
|
||||
$arr['xprof_hash'] = $hash;
|
||||
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('','',$profile['birthday'],'Y-m-d')); // !!!! check this for 0000 year
|
||||
$arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0);
|
||||
$arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_gender'] = (($profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_marital'] = (($profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_sexual'] = (($profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_locale'] = (($profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_region'] = (($profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_postcode'] = (($profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_country'] = (($profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_about'] = (($profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_homepage'] = (($profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_hometown'] = (($profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_hash'] = $hash;
|
||||
$arr['xprof_dob'] = '0000-00-00';
|
||||
|
||||
if (isset($profile['birthday'])) {
|
||||
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00')
|
||||
? $profile['birthday']
|
||||
: datetime_convert('', '', $profile['birthday'], 'Y-m-d')); // !!!! check this for 0000 year
|
||||
}
|
||||
|
||||
$arr['xprof_age'] = ((isset($profile['age']) && $profile['age']) ? intval($profile['age']) : 0);
|
||||
$arr['xprof_desc'] = ((isset($profile['description']) && $profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_gender'] = ((isset($profile['gender']) && $profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_marital'] = ((isset($profile['marital']) && $profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_sexual'] = ((isset($profile['sexual']) && $profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_locale'] = ((isset($profile['locale']) && $profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_region'] = ((isset($profile['region']) && $profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_postcode'] = ((isset($profile['postcode']) && $profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_country'] = ((isset($profile['country']) && $profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_about'] = ((isset($profile['about']) && $profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_homepage'] = ((isset($profile['homepage']) && $profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_hometown'] = ((isset($profile['hometown']) && $profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
|
||||
$clean = array();
|
||||
if (array_key_exists('keywords', $profile) and is_array($profile['keywords'])) {
|
||||
self::import_directory_keywords($hash,$profile['keywords']);
|
||||
|
||||
foreach ($profile['keywords'] as $kw) {
|
||||
if (in_array($kw, $clean)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false));
|
||||
$kw = trim($kw, ',');
|
||||
$clean[] = $kw;
|
||||
@@ -580,9 +631,6 @@ class Libzotdir {
|
||||
*/
|
||||
call_hooks('import_directory_profile', $d);
|
||||
|
||||
if (($d['update']) && (! $suppress_update))
|
||||
self::update_modtime($arr['xprof_hash'],random_string() . '@' . \App::get_hostname(), $addr, $ud_flags);
|
||||
|
||||
return $d['update'];
|
||||
}
|
||||
|
||||
@@ -600,6 +648,10 @@ class Libzotdir {
|
||||
dbesc($hash)
|
||||
);
|
||||
|
||||
$xchan = q("select xchan_censored from xchan where xchan_hash = '%s'",
|
||||
dbesc($hash)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
foreach($r as $rr)
|
||||
$existing[] = $rr['xtag_term'];
|
||||
@@ -607,6 +659,10 @@ class Libzotdir {
|
||||
|
||||
$clean = array();
|
||||
foreach($keywords as $kw) {
|
||||
if (in_array($kw, $clean)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false));
|
||||
$kw = trim($kw, ',');
|
||||
$clean[] = $kw;
|
||||
@@ -621,9 +677,10 @@ class Libzotdir {
|
||||
}
|
||||
foreach($clean as $x) {
|
||||
if(! in_array($x, $existing)) {
|
||||
$r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', 0 )",
|
||||
$r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', %d )",
|
||||
dbesc($hash),
|
||||
dbesc($x)
|
||||
dbesc($x),
|
||||
intval($xchan[0]['xchan_censored'])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -633,40 +690,83 @@ class Libzotdir {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param string $hash
|
||||
* @param string $guid
|
||||
* @param string $addr
|
||||
* @param int $flags (optional) default 0
|
||||
* @param string $hash the channel hash
|
||||
* @param string $addr the channel url
|
||||
* @param bool $bump_date (optional) default true
|
||||
*/
|
||||
|
||||
static function update_modtime($hash, $guid, $addr, $flags = 0) {
|
||||
static function update($hash, $addr, $bump_date = true, $flag = null) {
|
||||
|
||||
$dirmode = intval(get_config('system', 'directory_mode'));
|
||||
$dirmode = intval(Config::Get('system', 'directory_mode'));
|
||||
|
||||
if($dirmode == DIRECTORY_MODE_NORMAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($hash) || empty($guid) || empty($addr)) {
|
||||
if (empty($hash) || empty($addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if($flags) {
|
||||
q("insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )",
|
||||
dbesc($hash),
|
||||
dbesc($guid),
|
||||
dbesc(datetime_convert()),
|
||||
intval($flags),
|
||||
dbesc($addr)
|
||||
);
|
||||
$u = q("SELECT * FROM updates WHERE ud_hash = '%s' LIMIT 1",
|
||||
dbesc($hash)
|
||||
);
|
||||
|
||||
$date_sql = '';
|
||||
if ($bump_date) {
|
||||
$date_sql = "ud_date = '" . dbesc(datetime_convert()) . "',";
|
||||
}
|
||||
else {
|
||||
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d)>0 ",
|
||||
intval(UPDATE_FLAGS_UPDATED),
|
||||
|
||||
$flag_sql = '';
|
||||
if ($flag !== null) {
|
||||
$flag_sql = "ud_flags = '" . intval($flag) . "',";
|
||||
}
|
||||
|
||||
|
||||
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(z_root()),
|
||||
dbesc($addr),
|
||||
intval(UPDATE_FLAGS_UPDATED)
|
||||
intval($u[0]['ud_id'])
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
q("INSERT INTO updates (ud_hash, ud_host, ud_date, ud_addr, ud_flags) VALUES ( '%s', '%s', '%s', '%s', %d )",
|
||||
dbesc($hash),
|
||||
dbesc(z_root()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($addr),
|
||||
intval($flag)
|
||||
);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief deletes a entry in updates by hash
|
||||
*
|
||||
* @param string $hash the channel hash
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
static function delete_by_hash($hash) {
|
||||
if (!$hash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$x = q("DELETE FROM updates WHERE ud_hash = '%s'",
|
||||
dbesc($hash)
|
||||
);
|
||||
|
||||
if ($x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ class MessageFilter {
|
||||
|
||||
public static function evaluate($item, $incl, $excl) {
|
||||
|
||||
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/x-multicode'));
|
||||
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
|
||||
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
|
||||
|
||||
$lang = null;
|
||||
@@ -25,11 +25,23 @@ class MessageFilter {
|
||||
|
||||
if ($exclude) {
|
||||
foreach ($exclude as $word) {
|
||||
$word = trim($word);
|
||||
$word = html_entity_decode(trim($word));
|
||||
if (! $word) {
|
||||
continue;
|
||||
}
|
||||
if (substr($word, 0, 1) === '#' && $tags) {
|
||||
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;
|
||||
@@ -51,10 +63,6 @@ class MessageFilter {
|
||||
}
|
||||
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
|
||||
return false;
|
||||
} elseif ((strpos($word, 'lang=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 5))) == 0)) {
|
||||
return false;
|
||||
} elseif ((strpos($word, 'lang!=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 6))) != 0)) {
|
||||
return false;
|
||||
} elseif (stristr($text, $word) !== false) {
|
||||
return false;
|
||||
}
|
||||
@@ -65,11 +73,23 @@ class MessageFilter {
|
||||
|
||||
if ($include) {
|
||||
foreach ($include as $word) {
|
||||
$word = trim($word);
|
||||
$word = html_entity_decode(trim($word));
|
||||
if (! $word) {
|
||||
continue;
|
||||
}
|
||||
if (substr($word, 0, 1) === '#' && $tags) {
|
||||
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;
|
||||
@@ -91,10 +111,6 @@ class MessageFilter {
|
||||
}
|
||||
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
|
||||
return true;
|
||||
} elseif ((strpos($word, 'lang=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 5))) == 0)) {
|
||||
return true;
|
||||
} elseif ((strpos($word, 'lang!=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 6))) != 0)) {
|
||||
return true;
|
||||
} elseif (stristr($text, $word) !== false) {
|
||||
return true;
|
||||
}
|
||||
@@ -123,7 +139,8 @@ class MessageFilter {
|
||||
* - ?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
|
||||
@@ -205,6 +222,15 @@ class MessageFilter {
|
||||
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;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x) {
|
||||
|
||||
34
Zotlabs/Lib/Multibase.php
Normal file
34
Zotlabs/Lib/Multibase.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use StephenHill\Base58;
|
||||
|
||||
class Multibase {
|
||||
|
||||
protected $key = null;
|
||||
|
||||
public function __construct() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function publicKey($key) {
|
||||
$base58 = new Base58();
|
||||
$raw = hex2bin('ed01') . sodium_base642bin($key, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
|
||||
return 'z' . $base58->encode($raw);
|
||||
}
|
||||
|
||||
public function secretKey($key) {
|
||||
$base58 = new Base58();
|
||||
$raw = hex2bin('8026') . sodium_base642bin($key, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
|
||||
return 'z' . $base58->encode($raw);
|
||||
}
|
||||
|
||||
public function decode($key, $binary = false) {
|
||||
$base58 = new Base58();
|
||||
$key = substr($key,1);
|
||||
$raw = $base58->decode($key);
|
||||
$binaryKey = substr($raw, 2);
|
||||
return $binary ? $binaryKey : sodium_bin2base64($binaryKey, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
define ( 'NWIKI_ITEM_RESOURCE_TYPE', 'nwiki' );
|
||||
|
||||
class NativeWiki {
|
||||
|
||||
|
||||
public static function listwikis($channel, $observer_hash) {
|
||||
|
||||
$sql_extra = item_permissions_sql($channel['channel_id'], $observer_hash);
|
||||
$wikis = q("SELECT * FROM item
|
||||
WHERE resource_type = '%s' AND mid = parent_mid AND uid = %d AND item_deleted = 0 $sql_extra",
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
if($wikis) {
|
||||
foreach($wikis as &$w) {
|
||||
|
||||
$w['json_allow_cid'] = acl2json($w['allow_cid']);
|
||||
$w['json_allow_gid'] = acl2json($w['allow_gid']);
|
||||
$w['json_deny_cid'] = acl2json($w['deny_cid']);
|
||||
$w['json_deny_gid'] = acl2json($w['deny_gid']);
|
||||
|
||||
$w['rawName'] = get_iconfig($w, 'wiki', 'rawName');
|
||||
$w['htmlName'] = escape_tags($w['rawName']);
|
||||
//$w['urlName'] = urlencode(urlencode($w['rawName']));
|
||||
$w['urlName'] = self::name_encode($w['rawName']);
|
||||
$w['mimeType'] = get_iconfig($w, 'wiki', 'mimeType');
|
||||
$w['typelock'] = get_iconfig($w, 'wiki', 'typelock');
|
||||
$w['lockstate'] = (($w['allow_cid'] || $w['allow_gid'] || $w['deny_cid'] || $w['deny_gid']) ? 'lock' : 'unlock');
|
||||
}
|
||||
}
|
||||
// TODO: query db for wikis the observer can access. Return with two lists, for read and write access
|
||||
return array('wikis' => $wikis);
|
||||
}
|
||||
|
||||
|
||||
public static function create_wiki($channel, $observer_hash, $wiki, $acl) {
|
||||
|
||||
$resource_id = new_uuid();
|
||||
$uuid = new_uuid();
|
||||
|
||||
$ac = $acl->get();
|
||||
$mid = z_root() . '/item/' . $uuid;
|
||||
|
||||
$arr = array(); // Initialize the array of parameters for the post
|
||||
$item_hidden = ((intval($wiki['postVisible']) === 0) ? 1 : 0);
|
||||
$wiki_url = z_root() . '/wiki/' . $channel['channel_address'] . '/' . $wiki['urlName'];
|
||||
$arr['aid'] = $channel['channel_account_id'];
|
||||
$arr['uuid'] = $uuid;
|
||||
$arr['uid'] = $channel['channel_id'];
|
||||
$arr['mid'] = $mid;
|
||||
$arr['parent_mid'] = $mid;
|
||||
$arr['item_hidden'] = $item_hidden;
|
||||
$arr['resource_type'] = NWIKI_ITEM_RESOURCE_TYPE;
|
||||
$arr['resource_id'] = $resource_id;
|
||||
$arr['owner_xchan'] = $channel['channel_hash'];
|
||||
$arr['author_xchan'] = $observer_hash;
|
||||
$arr['plink'] = $mid;
|
||||
$arr['llink'] = z_root() . '/display/' . gen_link_id($mid);
|
||||
$arr['title'] = $wiki['htmlName']; // name of new wiki;
|
||||
$arr['allow_cid'] = $ac['allow_cid'];
|
||||
$arr['allow_gid'] = $ac['allow_gid'];
|
||||
$arr['deny_cid'] = $ac['deny_cid'];
|
||||
$arr['deny_gid'] = $ac['deny_gid'];
|
||||
$arr['item_wall'] = 1;
|
||||
$arr['item_origin'] = 1;
|
||||
$arr['item_thread_top'] = 1;
|
||||
$arr['item_private'] = intval($acl->is_private());
|
||||
$arr['verb'] = ACTIVITY_CREATE;
|
||||
$arr['obj_type'] = 'Document';
|
||||
$arr['body'] = '[table][tr][td][h1]New Wiki[/h1][/td][/tr][tr][td][zrl=' . $wiki_url . ']' . $wiki['htmlName'] . '[/zrl][/td][/tr][/table]';
|
||||
|
||||
$arr['public_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_wiki'),true);
|
||||
|
||||
// Save the wiki name information using iconfig. This is shareable.
|
||||
if(! set_iconfig($arr, 'wiki', 'rawName', $wiki['rawName'], true)) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
if(! set_iconfig($arr, 'wiki', 'mimeType', $wiki['mimeType'], true)) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
|
||||
set_iconfig($arr,'wiki','typelock',$wiki['typelock'],true);
|
||||
|
||||
$post = item_store($arr);
|
||||
|
||||
$item_id = $post['item_id'];
|
||||
|
||||
if($item_id) {
|
||||
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'activity', $item_id));
|
||||
return array('item' => $post['item'], 'item_id' => $item_id, 'success' => true);
|
||||
}
|
||||
else {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function update_wiki($channel_id, $observer_hash, $arr, $acl) {
|
||||
|
||||
$w = self::get_wiki($channel_id, $observer_hash, $arr['resource_id']);
|
||||
$item = $w['wiki'];
|
||||
|
||||
if(! $item) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
|
||||
$x = $acl->get();
|
||||
|
||||
$item['allow_cid'] = $x['allow_cid'];
|
||||
$item['allow_gid'] = $x['allow_gid'];
|
||||
$item['deny_cid'] = $x['deny_cid'];
|
||||
$item['deny_gid'] = $x['deny_gid'];
|
||||
$item['item_private'] = intval($acl->is_private());
|
||||
|
||||
$update_title = false;
|
||||
|
||||
if($item['title'] !== $arr['updateRawName']) {
|
||||
$update_title = true;
|
||||
$item['title'] = $arr['updateRawName'];
|
||||
}
|
||||
|
||||
$update = item_store_update($item);
|
||||
|
||||
$item_id = $update['item_id'];
|
||||
|
||||
// update acl for any existing wiki pages
|
||||
|
||||
q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d where resource_type = 'nwikipage' and resource_id = '%s'",
|
||||
dbesc($item['allow_cid']),
|
||||
dbesc($item['allow_gid']),
|
||||
dbesc($item['deny_cid']),
|
||||
dbesc($item['deny_gid']),
|
||||
dbesc($item['item_private']),
|
||||
dbesc($arr['resource_id'])
|
||||
);
|
||||
|
||||
|
||||
if($update['item_id']) {
|
||||
info( t('Wiki updated successfully'));
|
||||
if($update_title) {
|
||||
// Update the wiki name information using iconfig.
|
||||
if(! set_iconfig($update['item_id'], 'wiki', 'rawName', $arr['updateRawName'], true)) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
}
|
||||
return array('item' => $update['item'], 'item_id' => $update['item_id'], 'success' => $update['success']);
|
||||
}
|
||||
else {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function sync_a_wiki_item($uid,$id,$resource_id) {
|
||||
|
||||
$r = q("SELECT * from item WHERE uid = %d AND ( id = %d OR ( resource_type = '%s' and resource_id = '%s' )) ",
|
||||
intval($uid),
|
||||
intval($id),
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
if($r) {
|
||||
|
||||
$q = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s'",
|
||||
dbesc($r[0]['resource_id'])
|
||||
);
|
||||
if($q) {
|
||||
$r = array_merge($r,$q);
|
||||
}
|
||||
xchan_query($r);
|
||||
$sync_item = fetch_post_tags($r);
|
||||
if($sync_item) {
|
||||
$pkt = [];
|
||||
foreach($sync_item as $w) {
|
||||
$pkt[] = encode_item($w,true);
|
||||
}
|
||||
Libsync::build_sync_packet($uid,array('wiki' => $pkt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function delete_wiki($channel_id,$observer_hash,$resource_id) {
|
||||
|
||||
$w = self::get_wiki($channel_id,$observer_hash,$resource_id);
|
||||
if(! $w['wiki']) {
|
||||
return [ 'success' => false ];
|
||||
}
|
||||
else {
|
||||
|
||||
$r = q("SELECT id FROM item WHERE uid = %s AND resource_id = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
|
||||
$ids = array_column($r, 'id');
|
||||
drop_items($ids, true, DROPITEM_PHASE1);
|
||||
|
||||
info(t('Wiki files deleted successfully'));
|
||||
|
||||
return [ 'success' => true ];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function get_wiki($channel_id, $observer_hash, $resource_id) {
|
||||
|
||||
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
|
||||
|
||||
$item = q("SELECT * FROM item WHERE uid = %d AND resource_type = '%s' AND resource_id = '%s' AND item_deleted = 0
|
||||
$sql_extra ORDER BY id LIMIT 1",
|
||||
intval($channel_id),
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
if(! $item) {
|
||||
return [ 'wiki' => null ];
|
||||
}
|
||||
else {
|
||||
|
||||
$w = $item[0]; // wiki item table record
|
||||
// Get wiki metadata
|
||||
$rawName = get_iconfig($w, 'wiki', 'rawName');
|
||||
$mimeType = get_iconfig($w, 'wiki', 'mimeType');
|
||||
$typelock = get_iconfig($w, 'wiki', 'typelock');
|
||||
|
||||
return array(
|
||||
'wiki' => $w,
|
||||
'rawName' => $rawName,
|
||||
'htmlName' => escape_tags($rawName),
|
||||
//'urlName' => urlencode(urlencode($rawName)),
|
||||
'urlName' => self::name_encode($rawName),
|
||||
'mimeType' => $mimeType,
|
||||
'typelock' => $typelock
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function exists_by_name($uid, $urlName) {
|
||||
|
||||
$sql_extra = item_permissions_sql($uid);
|
||||
|
||||
$item = q("SELECT item.id, resource_id FROM item left join iconfig on iconfig.iid = item.id
|
||||
WHERE resource_type = '%s' AND iconfig.v = '%s' AND uid = %d
|
||||
AND item_deleted = 0 $sql_extra limit 1",
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
//dbesc(urldecode($urlName)),
|
||||
dbesc(self::name_decode($urlName)),
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
if($item) {
|
||||
return array('id' => $item[0]['id'], 'resource_id' => $item[0]['resource_id']);
|
||||
}
|
||||
else {
|
||||
return array('id' => null, 'resource_id' => null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function get_permissions($resource_id, $owner_id, $observer_hash) {
|
||||
|
||||
// TODO: For now, only the owner can edit
|
||||
$sql_extra = item_permissions_sql($owner_id, $observer_hash);
|
||||
|
||||
if(local_channel() && local_channel() == $owner_id) {
|
||||
return [ 'read' => true, 'write' => true, 'success' => true ];
|
||||
}
|
||||
|
||||
$r = q("SELECT * FROM item WHERE uid = %d and resource_type = '%s' AND resource_id = '%s' $sql_extra LIMIT 1",
|
||||
intval($owner_id),
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
return array('read' => false, 'write' => false, 'success' => true);
|
||||
}
|
||||
else {
|
||||
$write = perm_is_allowed($owner_id, $observer_hash,'write_wiki');
|
||||
return array('read' => true, 'write' => $write, 'success' => true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function name_encode ($string) {
|
||||
|
||||
$string = html_entity_decode($string);
|
||||
$encoding = mb_internal_encoding();
|
||||
mb_internal_encoding("UTF-8");
|
||||
$ret = mb_ereg_replace_callback ('[^A-Za-z0-9\-\_\.\~]',function ($char) {
|
||||
$charhex = unpack('H*',$char[0]);
|
||||
$ret = '('.$charhex[1].')';
|
||||
return $ret;
|
||||
}
|
||||
,$string);
|
||||
mb_internal_encoding($encoding);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
public static function name_decode ($string) {
|
||||
|
||||
$encoding = mb_internal_encoding();
|
||||
mb_internal_encoding("UTF-8");
|
||||
$ret = mb_ereg_replace_callback ('(\(([0-9a-f]+)\))',function ($chars) {
|
||||
return pack('H*',$chars[2]);
|
||||
}
|
||||
,$string);
|
||||
mb_internal_encoding($encoding);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,725 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Access\PermissionLimits;
|
||||
|
||||
class NativeWikiPage {
|
||||
|
||||
static public function page_list($channel_id, $observer_hash, $resource_id) {
|
||||
|
||||
// TODO: Create item table records for pages so that metadata like title can be applied
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
$pages[] = [
|
||||
'resource_id' => '',
|
||||
'title' => 'Home',
|
||||
'url' => 'Home',
|
||||
'link_id' => 'id_wiki_home_0'
|
||||
];
|
||||
|
||||
$sql_extra = item_permissions_sql($channel_id, $observer_hash);
|
||||
|
||||
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and item_deleted = 0
|
||||
$sql_extra order by title asc",
|
||||
dbesc($resource_id),
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r) {
|
||||
$x = [];
|
||||
$y = [];
|
||||
|
||||
foreach ($r as $rv) {
|
||||
if (!in_array($rv['mid'], $x)) {
|
||||
$y[] = $rv;
|
||||
$x[] = $rv['mid'];
|
||||
}
|
||||
}
|
||||
|
||||
$items = fetch_post_tags($y, true);
|
||||
|
||||
foreach ($items as $page_item) {
|
||||
$title = get_iconfig($page_item['id'], 'nwikipage', 'pagetitle', t('(No Title)'));
|
||||
if (urldecode($title) !== 'Home') {
|
||||
$pages[] = [
|
||||
'resource_id' => $resource_id,
|
||||
'title' => escape_tags($title),
|
||||
//'url' => str_replace('%2F','/',urlencode(str_replace('%2F','/',urlencode($title)))),
|
||||
'url' => NativeWiki::name_encode($title),
|
||||
'link_id' => 'id_' . substr($resource_id, 0, 10) . '_' . $page_item['id']
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ['pages' => $pages, 'wiki' => $w];
|
||||
}
|
||||
|
||||
|
||||
static public function create_page($channel, $observer_hash, $name, $resource_id, $mimetype = 'text/bbcode') {
|
||||
|
||||
logger('mimetype: ' . $mimetype);
|
||||
|
||||
if (!in_array($mimetype, ['text/markdown', 'text/bbcode', 'text/plain', 'text/html']))
|
||||
$mimetype = 'text/markdown';
|
||||
|
||||
$w = NativeWiki::get_wiki($channel['channel_id'], $observer_hash, $resource_id);
|
||||
|
||||
if (!$w['wiki']) {
|
||||
return ['content' => null, 'message' => 'Error reading wiki', 'success' => false];
|
||||
}
|
||||
|
||||
// backslashes won't work well in the javascript functions
|
||||
$name = str_replace('\\', '', $name);
|
||||
|
||||
$uuid = new_uuid();
|
||||
$mid = z_root() . '/item/' . $uuid;
|
||||
|
||||
// create an empty activity
|
||||
$arr = [];
|
||||
$arr['aid'] = $channel['channel_account_id'];
|
||||
$arr['uid'] = $channel['channel_id'];
|
||||
$arr['mid'] = $mid;
|
||||
$arr['parent_mid'] = $w['wiki']['mid'];
|
||||
$arr['parent'] = $w['wiki']['parent'];
|
||||
$arr['uuid'] = $uuid;
|
||||
$arr['item_hidden'] = $w['wiki']['item_hidden'];
|
||||
$arr['plink'] = $mid;
|
||||
$arr['llink'] = z_root() . '/display/' . gen_link_id($mid);
|
||||
$arr['author_xchan'] = $observer_hash;
|
||||
$arr['mimetype'] = $mimetype;
|
||||
$arr['title'] = $name;
|
||||
$arr['resource_type'] = 'nwikipage';
|
||||
$arr['resource_id'] = $resource_id;
|
||||
$arr['allow_cid'] = $w['wiki']['allow_cid'];
|
||||
$arr['allow_gid'] = $w['wiki']['allow_gid'];
|
||||
$arr['deny_cid'] = $w['wiki']['deny_cid'];
|
||||
$arr['deny_gid'] = $w['wiki']['deny_gid'];
|
||||
$arr['item_private'] = $w['wiki']['item_private'];
|
||||
$arr['item_wall'] = 1;
|
||||
$arr['item_origin'] = 1;
|
||||
$arr['item_thread_top'] = 1;
|
||||
$arr['verb'] = ACTIVITY_CREATE;
|
||||
$arr['obj_type'] = 'Document';
|
||||
// TODO: add an object?
|
||||
$arr['public_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'], 'view_wiki'), true);
|
||||
|
||||
// We may wish to change this some day.
|
||||
$arr['item_unpublished'] = 1;
|
||||
|
||||
set_iconfig($arr, 'nwikipage', 'pagetitle', (($name) ? $name : t('(No Title)')), true);
|
||||
$p = item_store($arr, false, false);
|
||||
|
||||
if ($p['item_id']) {
|
||||
$page = [
|
||||
'rawName' => $name,
|
||||
'htmlName' => escape_tags($name),
|
||||
//'urlName' => urlencode($name),
|
||||
'urlName' => NativeWiki::name_encode($name)
|
||||
|
||||
];
|
||||
|
||||
return ['page' => $page, 'item_id' => $p['item_id'], 'item' => $p['activity'], 'wiki' => $w, 'message' => '', 'success' => true];
|
||||
}
|
||||
return ['success' => false, 'message' => t('Wiki page create failed.')];
|
||||
}
|
||||
|
||||
|
||||
static public function rename_page($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
|
||||
$pageNewName = ((array_key_exists('pageNewName', $arr)) ? $arr['pageNewName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (!$w['wiki']) {
|
||||
return ['message' => t('Wiki not found.'), 'success' => false];
|
||||
}
|
||||
|
||||
|
||||
$ic = q("select * from iconfig left join item on iconfig.iid = item.id
|
||||
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageNewName)
|
||||
);
|
||||
|
||||
if ($ic) {
|
||||
return ['success' => false, 'message' => t('Destination name already exists')];
|
||||
}
|
||||
|
||||
|
||||
$ids = [];
|
||||
|
||||
$ic = q("select *, item.id as item_id from iconfig left join item on iconfig.iid = item.id
|
||||
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageUrlName)
|
||||
);
|
||||
|
||||
if ($ic) {
|
||||
foreach ($ic as $c) {
|
||||
set_iconfig($c['item_id'], 'nwikipage', 'pagetitle', $pageNewName);
|
||||
$ids[] = $c['item_id'];
|
||||
}
|
||||
|
||||
$str_ids = implode(',', $ids);
|
||||
q("update item set title = '%s' where id in ($str_ids)",
|
||||
dbesc($pageNewName)
|
||||
);
|
||||
|
||||
$page = [
|
||||
'rawName' => $pageNewName,
|
||||
'htmlName' => escape_tags($pageNewName),
|
||||
//'urlName' => urlencode(escape_tags($pageNewName))
|
||||
'urlName' => NativeWiki::name_encode($pageNewName)
|
||||
];
|
||||
|
||||
return ['success' => true, 'page' => $page];
|
||||
}
|
||||
|
||||
return ['success' => false, 'message' => t('Page not found')];
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function get_page_content($arr) {
|
||||
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? intval($arr['channel_id']) : 0);
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (!$w['wiki']) {
|
||||
return ['content' => null, 'message' => 'Error reading wiki', 'success' => false];
|
||||
}
|
||||
|
||||
$item = self::load_page($arr);
|
||||
|
||||
if ($item) {
|
||||
$content = $item['body'];
|
||||
|
||||
return [
|
||||
'content' => $content,
|
||||
'mimeType' => $w['mimeType'],
|
||||
'pageMimeType' => $item['mimetype'],
|
||||
'message' => '',
|
||||
'success' => true
|
||||
];
|
||||
}
|
||||
|
||||
return ['content' => null, 'message' => t('Error reading page content'), 'success' => false];
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function page_history($arr) {
|
||||
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (!$w['wiki']) {
|
||||
return ['history' => null, 'message' => 'Error reading wiki', 'success' => false];
|
||||
}
|
||||
|
||||
$items = self::load_page_history($arr);
|
||||
|
||||
$history = [];
|
||||
|
||||
if ($items) {
|
||||
$processed = 0;
|
||||
foreach ($items as $item) {
|
||||
if ($processed > 1000)
|
||||
break;
|
||||
$processed++;
|
||||
$history[] = [
|
||||
'revision' => $item['revision'],
|
||||
'date' => datetime_convert('UTC', date_default_timezone_get(), $item['edited']),
|
||||
'name' => $item['author']['xchan_name'],
|
||||
'title' => get_iconfig($item, 'nwikipage', 'commit_msg')
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
return ['success' => true, 'history' => $history];
|
||||
}
|
||||
|
||||
return ['success' => false];
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function load_page($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? $arr['channel_id'] : 0);
|
||||
$revision = ((array_key_exists('revision', $arr)) ? $arr['revision'] : (-1));
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if (!$w['wiki']) {
|
||||
return ['content' => null, 'message' => 'Error reading wiki', 'success' => false];
|
||||
}
|
||||
|
||||
$ids = '';
|
||||
|
||||
$ic = q("select * from iconfig left join item on iconfig.iid = item.id where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageUrlName)
|
||||
);
|
||||
|
||||
if ($ic) {
|
||||
foreach ($ic as $c) {
|
||||
if ($ids)
|
||||
$ids .= ',';
|
||||
$ids .= intval($c['iid']);
|
||||
}
|
||||
}
|
||||
|
||||
$sql_extra = item_permissions_sql($channel_id, $observer_hash);
|
||||
|
||||
if ($revision == (-1))
|
||||
$sql_extra .= " order by revision desc ";
|
||||
elseif ($revision)
|
||||
$sql_extra .= " and revision = " . intval($revision) . " ";
|
||||
|
||||
$r = null;
|
||||
|
||||
|
||||
if ($ids) {
|
||||
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and id in ( $ids ) $sql_extra limit 1",
|
||||
dbesc($resource_id),
|
||||
intval($channel_id)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$items = fetch_post_tags($r, true);
|
||||
return $items[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static public function load_page_history($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (!$w['wiki']) {
|
||||
return ['content' => null, 'message' => 'Error reading wiki', 'success' => false];
|
||||
}
|
||||
|
||||
$ids = '';
|
||||
|
||||
$ic = q("select * from iconfig left join item on iconfig.iid = item.id where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageUrlName)
|
||||
);
|
||||
|
||||
if ($ic) {
|
||||
foreach ($ic as $c) {
|
||||
if ($ids)
|
||||
$ids .= ',';
|
||||
$ids .= intval($c['iid']);
|
||||
}
|
||||
}
|
||||
|
||||
$sql_extra = item_permissions_sql($channel_id, $observer_hash);
|
||||
|
||||
$sql_extra .= " order by revision desc ";
|
||||
|
||||
$r = null;
|
||||
if ($ids) {
|
||||
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and id in ( $ids ) and item_deleted = 0 $sql_extra",
|
||||
dbesc($resource_id),
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r) {
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static public function save_page($arr) {
|
||||
$pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
|
||||
$content = ((array_key_exists('content', $arr)) ? $arr['content'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if (!$w['wiki']) {
|
||||
return ['message' => t('Error reading wiki'), 'success' => false];
|
||||
}
|
||||
|
||||
|
||||
// fetch the most recently saved revision.
|
||||
|
||||
$item = self::load_page($arr);
|
||||
|
||||
if (!$item) {
|
||||
return ['message' => t('Page not found'), 'success' => false];
|
||||
}
|
||||
|
||||
$mimetype = $item['mimetype'];
|
||||
|
||||
// change just the fields we need to change to create a revision;
|
||||
|
||||
unset($item['id']);
|
||||
unset($item['author']);
|
||||
$item['parent'] = 0;
|
||||
$item['body'] = $content;
|
||||
$item['author_xchan'] = $observer_hash;
|
||||
$item['revision'] = (($arr['revision']) ? intval($arr['revision']) + 1 : intval($item['revision']) + 1);
|
||||
$item['edited'] = datetime_convert();
|
||||
$item['mimetype'] = $mimetype;
|
||||
|
||||
if ($item['iconfig'] && is_array($item['iconfig']) && count($item['iconfig'])) {
|
||||
for ($x = 0; $x < count($item['iconfig']); $x++) {
|
||||
unset($item['iconfig'][$x]['id']);
|
||||
unset($item['iconfig'][$x]['iid']);
|
||||
}
|
||||
}
|
||||
|
||||
$ret = item_store($item, false, false);
|
||||
|
||||
if ($ret['item_id'])
|
||||
return ['message' => '', 'item_id' => $ret['item_id'], 'filename' => $pageUrlName, 'success' => true];
|
||||
else
|
||||
return ['message' => t('Page update failed.'), 'success' => false];
|
||||
}
|
||||
|
||||
|
||||
static public function delete_page($arr) {
|
||||
|
||||
$pageUrlName = (array_key_exists('pageUrlName', $arr) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = (array_key_exists('resource_id', $arr) ? $arr['resource_id'] : '');
|
||||
$observer_hash = (array_key_exists('observer_hash', $arr) ? $arr['observer_hash'] : '');
|
||||
$channel_id = (array_key_exists('channel_id', $arr) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (!$w['wiki']) {
|
||||
return ['success' => false, 'message' => t('Error reading wiki')];
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
|
||||
$ic = q("select * from iconfig left join item on iconfig.iid = item.id
|
||||
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageUrlName)
|
||||
);
|
||||
|
||||
if ($ic) {
|
||||
foreach ($ic as $c) {
|
||||
$ids[] = intval($c['iid']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($ids) {
|
||||
drop_items($ids, true, DROPITEM_PHASE1);
|
||||
return ['success' => true];
|
||||
}
|
||||
|
||||
return ['success' => false, 'message' => t('Nothing deleted')];
|
||||
}
|
||||
|
||||
|
||||
static public function revert_page($arr) {
|
||||
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
$commitHash = ((array_key_exists('commitHash', $arr)) ? $arr['commitHash'] : null);
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
if (!$commitHash) {
|
||||
return ['message' => 'No commit was provided', 'success' => false];
|
||||
}
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (!$w['wiki']) {
|
||||
return ['message' => 'Error reading wiki', 'success' => false];
|
||||
}
|
||||
|
||||
$x = $arr;
|
||||
|
||||
if (intval($commitHash) > 0) {
|
||||
unset($x['commitHash']);
|
||||
$x['revision'] = intval($commitHash) - 1;
|
||||
$loaded = self::load_page($x);
|
||||
|
||||
if ($loaded) {
|
||||
$content = $loaded['body'];
|
||||
return ['content' => $content, 'success' => true];
|
||||
}
|
||||
return ['success' => false];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public function compare_page($arr) {
|
||||
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
$compareCommit = ((array_key_exists('compareCommit', $arr)) ? $arr['compareCommit'] : 0);
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if (!$w['wiki']) {
|
||||
return ['message' => t('Error reading wiki'), 'success' => false];
|
||||
}
|
||||
|
||||
$x = $arr;
|
||||
$x['revision'] = (-1);
|
||||
|
||||
$currpage = self::load_page($x);
|
||||
if ($currpage)
|
||||
$currentContent = $currpage['body'];
|
||||
|
||||
$x['revision'] = $compareCommit;
|
||||
$comppage = self::load_page($x);
|
||||
if ($comppage)
|
||||
$compareContent = $comppage['body'];
|
||||
|
||||
if ($currpage && $comppage) {
|
||||
require_once('library/class.Diff.php');
|
||||
$diff = \Diff::toTable(\Diff::compare($currentContent, $compareContent));
|
||||
|
||||
return ['success' => true, 'diff' => $diff];
|
||||
}
|
||||
return ['success' => false, 'message' => t('Compare: object not found.')];
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function commit($arr) {
|
||||
|
||||
$commit_msg = ((array_key_exists('commit_msg', $arr)) ? $arr['commit_msg'] : t('Page updated'));
|
||||
$observer_hash = ((array_key_exists('observer_hash', $arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id', $arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
if (array_key_exists('resource_id', $arr)) {
|
||||
$resource_id = $arr['resource_id'];
|
||||
}
|
||||
else {
|
||||
return ['message' => t('Wiki resource_id required for git commit'), 'success' => false];
|
||||
}
|
||||
|
||||
$w = NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (!$w['wiki']) {
|
||||
return ['message' => t('Error reading wiki'), 'success' => false];
|
||||
}
|
||||
|
||||
|
||||
$page = self::load_page($arr);
|
||||
|
||||
if ($page) {
|
||||
set_iconfig($page['id'], 'nwikipage', 'commit_msg', escape_tags($commit_msg), true);
|
||||
return ['success' => true, 'item_id' => $page['id'], 'page' => $page];
|
||||
}
|
||||
|
||||
return ['success' => false, 'message' => t('Page not found.')];
|
||||
|
||||
}
|
||||
|
||||
static public function convert_links($s, $wikiURL) {
|
||||
|
||||
if (strpos($s, '[[') !== false) {
|
||||
preg_match_all("/\[\[(.*?)\]\]/", $s, $match);
|
||||
$pages = $pageURLs = [];
|
||||
foreach ($match[1] as $m) {
|
||||
// TODO: Why do we need to double urlencode for this to work?
|
||||
//$pageURLs[] = urlencode(urlencode(escape_tags($m)));
|
||||
$titleUri = explode('|', $m);
|
||||
$page = $titleUri[0] ?? '';
|
||||
$title = $titleUri[1] ?? $page;
|
||||
$pageURLs[] = NativeWiki::name_encode(escape_tags($page));
|
||||
$pages[] = $title;
|
||||
}
|
||||
$idx = 0;
|
||||
while (strpos($s, '[[') !== false) {
|
||||
$replace = '<a href="' . $wikiURL . '/' . $pageURLs[$idx] . '">' . $pages[$idx] . '</a>';
|
||||
$s = preg_replace("/\[\[(.*?)\]\]/", $replace, $s, 1);
|
||||
$idx++;
|
||||
}
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
static public function render_page_history($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
|
||||
$pageHistory = self::page_history([
|
||||
'channel_id' => App::$profile_uid,
|
||||
'observer_hash' => get_observer_hash(),
|
||||
'resource_id' => $resource_id,
|
||||
'pageUrlName' => $pageUrlName
|
||||
]);
|
||||
|
||||
return replace_macros(get_markup_template('nwiki_page_history.tpl'), [
|
||||
'$pageHistory' => $pageHistory['history'],
|
||||
'$permsWrite' => $arr['permsWrite'],
|
||||
'$name_lbl' => t('Name'),
|
||||
'$msg_label' => t('Message', 'wiki_history'),
|
||||
'$date_lbl' => t('Date'),
|
||||
'$revert_btn' => t('Revert'),
|
||||
'$compare_btn' => t('Compare')
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replace the instances of the string [toc] with a list element that will be populated by
|
||||
* a table of contents by the JavaScript library
|
||||
* @param string $s
|
||||
* @return string
|
||||
*/
|
||||
static public function generate_toc($s) {
|
||||
if (strpos($s, '[toc]') !== false) {
|
||||
//$toc_md = wiki_toc($s); // Generate Markdown-formatted list prior to HTML render
|
||||
$toc_md = '<ul id="wiki-toc"></ul>'; // use the available jQuery plugin http://ndabas.github.io/toc/
|
||||
$s = preg_replace("/\[toc\]/", $toc_md, $s, -1);
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a select set of bbcode tags. Much of the code is copied from include/bbcode.php
|
||||
* @param string $s
|
||||
* @return string
|
||||
*/
|
||||
static public function bbcode($s) {
|
||||
|
||||
$s = str_replace(['[baseurl]', '[sitename]'], [z_root(), get_config('system', 'sitename')], $s);
|
||||
|
||||
$s = preg_replace_callback("/\[observer\.language\=(.*?)\](.*?)\[\/observer\]/ism", 'oblanguage_callback', $s);
|
||||
|
||||
$s = preg_replace_callback("/\[observer\.language\!\=(.*?)\](.*?)\[\/observer\]/ism", 'oblanguage_necallback', $s);
|
||||
|
||||
|
||||
$observer = App::get_observer();
|
||||
if ($observer) {
|
||||
$s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">';
|
||||
$s2 = '</span>';
|
||||
$obsBaseURL = $observer['xchan_connurl'];
|
||||
$obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
|
||||
$s = str_replace('[observer.baseurl]', $obsBaseURL, $s);
|
||||
$s = str_replace('[observer.url]', $observer['xchan_url'], $s);
|
||||
$s = str_replace('[observer.name]', $s1 . $observer['xchan_name'] . $s2, $s);
|
||||
$s = str_replace('[observer.address]', $s1 . $observer['xchan_addr'] . $s2, $s);
|
||||
$s = str_replace('[observer.webname]', substr($observer['xchan_addr'], 0, strpos($observer['xchan_addr'], '@')), $s);
|
||||
$s = str_replace('[observer.photo]', '', $s);
|
||||
}
|
||||
else {
|
||||
$s = str_replace('[observer.baseurl]', '', $s);
|
||||
$s = str_replace('[observer.url]', '', $s);
|
||||
$s = str_replace('[observer.name]', '', $s);
|
||||
$s = str_replace('[observer.address]', '', $s);
|
||||
$s = str_replace('[observer.webname]', '', $s);
|
||||
$s = str_replace('[observer.photo]', '', $s);
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
static public function get_file_ext($arr) {
|
||||
|
||||
if ($arr['mimetype'] === 'text/bbcode')
|
||||
return '.bb';
|
||||
elseif ($arr['mimetype'] === 'text/markdown')
|
||||
return '.md';
|
||||
elseif ($arr['mimetype'] === 'text/plain')
|
||||
return '.txt';
|
||||
|
||||
}
|
||||
|
||||
// This function is derived from
|
||||
// http://stackoverflow.com/questions/32068537/generate-table-of-contents-from-markdown-in-php
|
||||
static public function toc($content) {
|
||||
// ensure using only "\n" as line-break
|
||||
$source = str_replace(["\r\n", "\r"], "\n", $content);
|
||||
|
||||
// look for markdown TOC items
|
||||
preg_match_all(
|
||||
'/^(?:=|-|#).*$/m',
|
||||
$source,
|
||||
$matches,
|
||||
PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
|
||||
);
|
||||
|
||||
// preprocess: iterate matched lines to create an array of items
|
||||
// where each item is an array(level, text)
|
||||
$file_size = strlen($source);
|
||||
foreach ($matches[0] as $item) {
|
||||
$found_mark = substr($item[0], 0, 1);
|
||||
if ($found_mark == '#') {
|
||||
// text is the found item
|
||||
$item_text = $item[0];
|
||||
$item_level = strrpos($item_text, '#') + 1;
|
||||
$item_text = substr($item_text, $item_level);
|
||||
}
|
||||
else {
|
||||
// text is the previous line (empty if <hr>)
|
||||
$item_offset = $item[1];
|
||||
$prev_line_offset = strrpos($source, "\n", -($file_size - $item_offset + 2));
|
||||
$item_text =
|
||||
substr($source, $prev_line_offset, $item_offset - $prev_line_offset - 1);
|
||||
$item_text = trim($item_text);
|
||||
$item_level = $found_mark == '=' ? 1 : 2;
|
||||
}
|
||||
if (!trim($item_text) or strpos($item_text, '|') !== FALSE) {
|
||||
// item is an horizontal separator or a table header, don't mind
|
||||
continue;
|
||||
}
|
||||
$raw_toc[] = ['level' => $item_level, 'text' => trim($item_text)];
|
||||
}
|
||||
$o = '';
|
||||
foreach ($raw_toc as $t) {
|
||||
$level = intval($t['level']);
|
||||
$text = $t['text'];
|
||||
switch ($level) {
|
||||
case 1:
|
||||
$li = '* ';
|
||||
break;
|
||||
case 2:
|
||||
$li = ' * ';
|
||||
break;
|
||||
case 3:
|
||||
$li = ' * ';
|
||||
break;
|
||||
case 4:
|
||||
$li = ' * ';
|
||||
break;
|
||||
default:
|
||||
$li = '* ';
|
||||
break;
|
||||
}
|
||||
$o .= $li . $text . "\n";
|
||||
}
|
||||
return $o;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -117,7 +117,7 @@ class PermissionDescription {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an icon css class name if an appropriate one is available, e.g. "fa-globe" for Public,
|
||||
* Returns an icon css class name if an appropriate one is available, e.g. "bi-globe" for Public,
|
||||
* otherwise returns empty string.
|
||||
*
|
||||
* @return string icon css class name (often FontAwesome)
|
||||
@@ -125,12 +125,12 @@ class PermissionDescription {
|
||||
public function get_permission_icon() {
|
||||
|
||||
switch($this->channel_perm) {
|
||||
case 0:/* only me */ return 'fa-eye-slash';
|
||||
case PERMS_PUBLIC: return 'fa-globe';
|
||||
case PERMS_NETWORK: return 'fa-share-alt-square'; // fa-share-alt-square is very similiar to the hubzilla logo, but we should create our own logo class to use
|
||||
case PERMS_SITE: return 'fa-sitemap';
|
||||
case PERMS_CONTACTS: return 'fa-group';
|
||||
case PERMS_SPECIFIC: return 'fa-list';
|
||||
case 0:/* only me */ return 'bi-eye-slash';
|
||||
case PERMS_PUBLIC: return 'bi-globe';
|
||||
case PERMS_NETWORK: return 'bi-share'; // bi-share is very similiar to the hubzilla logo, but we should create our own logo class to use
|
||||
case PERMS_SITE: return 'bi-geo';
|
||||
case PERMS_CONTACTS: return 'bi-people';
|
||||
case PERMS_SPECIFIC: return 'bi-list-ul';
|
||||
case PERMS_AUTHED: return '';
|
||||
case PERMS_PENDING: return '';
|
||||
default: return '';
|
||||
|
||||
@@ -57,7 +57,6 @@ class Queue {
|
||||
outq_priority = outq_priority + %d,
|
||||
outq_scheduled = '%s'
|
||||
WHERE outq_hash = '%s'",
|
||||
|
||||
dbesc(datetime_convert()),
|
||||
intval($add_priority),
|
||||
dbesc($next),
|
||||
@@ -65,16 +64,38 @@ class Queue {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static function remove($id,$channel_id = 0) {
|
||||
logger('queue: remove queue item ' . $id,LOGGER_DEBUG);
|
||||
public static function remove($id, $channel_id = 0) {
|
||||
logger('queue: remove queue item ' . $id, LOGGER_DEBUG);
|
||||
$sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : '');
|
||||
|
||||
q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra",
|
||||
// figure out what endpoint it is going to.
|
||||
$record = q("select outq_posturl from outq where outq_hash = '%s' $sql_extra",
|
||||
dbesc($id)
|
||||
);
|
||||
}
|
||||
|
||||
if ($record) {
|
||||
q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra",
|
||||
dbesc($id)
|
||||
);
|
||||
|
||||
// If there's anything remaining in the queue for this site, move one of them to the next active
|
||||
// queue run by setting outq_scheduled back to the present. We may be attempting to deliver it
|
||||
// as a 'piled_up' delivery, but this ensures the site has an active queue entry as long as queued
|
||||
// entries still exist for it. This fixes an issue where one immediate delivery left everything
|
||||
// else for that site undeliverable since all the other entries had been pushed far into the future.
|
||||
|
||||
$r = q("SELECT outq_hash, outq_posturl FROM outq WHERE outq_posturl = '%s' LIMIT 1",
|
||||
dbesc($record[0]['outq_posturl'])
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$hashes = ids_to_querystr($r, 'outq_hash', true);
|
||||
$x = q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_hash IN ($hashes)",
|
||||
dbesc(datetime_convert())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function remove_by_posturl($posturl) {
|
||||
logger('queue: remove queue posturl ' . $posturl,LOGGER_DEBUG);
|
||||
@@ -84,8 +105,6 @@ class Queue {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static function set_delivered($id,$channel = 0) {
|
||||
logger('queue: set delivered ' . $id,LOGGER_DEBUG);
|
||||
$sql_extra = (($channel['channel_id']) ? " and outq_channel = " . intval($channel['channel_id']) . " " : '');
|
||||
@@ -110,21 +129,30 @@ class Queue {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hash = $arr['hash'] ?? '';
|
||||
$account_id = $arr['account_id'] ?? 0;
|
||||
$channel_id = $arr['channel_id'] ?? 0;
|
||||
$driver = $arr['driver'] ?? 'zot6';
|
||||
$posturl = $arr['posturl'] ?? '';
|
||||
$priority = $arr['priority'] ?? 0;
|
||||
$notify = $arr['notify'] ?? '';
|
||||
$msg = $arr['msg'] ?? '';
|
||||
|
||||
$x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority,
|
||||
outq_created, outq_updated, outq_scheduled, outq_notify, outq_msg )
|
||||
values ( '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s' )",
|
||||
dbesc($arr['hash']),
|
||||
intval($arr['account_id']),
|
||||
intval($arr['channel_id']),
|
||||
dbesc(($arr['driver']) ? $arr['driver'] : 'zot6'),
|
||||
dbesc($arr['posturl']),
|
||||
dbesc($hash),
|
||||
intval($account_id),
|
||||
intval($channel_id),
|
||||
dbesc($driver),
|
||||
dbesc($posturl),
|
||||
intval(1),
|
||||
intval(isset($arr['priority']) ? $arr['priority'] : 0),
|
||||
intval($priority),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($arr['notify']),
|
||||
dbesc(($arr['msg']) ? $arr['msg'] : '')
|
||||
dbesc($notify),
|
||||
dbesc($msg)
|
||||
);
|
||||
return $x;
|
||||
|
||||
@@ -143,17 +171,19 @@ class Queue {
|
||||
$y = q("select site_update, site_dead from site where site_url = '%s' ",
|
||||
dbesc($base)
|
||||
);
|
||||
if($y) {
|
||||
if(intval($y[0]['site_dead'])) {
|
||||
|
||||
if ($y) {
|
||||
// Don't bother delivering if the site is dead.
|
||||
// And if we haven't heard from the site in over a month - let them through but 3 strikes you're out.
|
||||
if (intval($y[0]['site_dead']) || ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month') && $outq['outq_priority'] > 20)) {
|
||||
q("update dreport set dreport_result = '%s' where dreport_queue = '%s'",
|
||||
dbesc('site dead'),
|
||||
dbesc($outq['outq_hash'])
|
||||
);
|
||||
self::remove_by_posturl($outq['outq_posturl']);
|
||||
logger('dead site ignored ' . $base);
|
||||
return;
|
||||
}
|
||||
if($y[0]['site_update'] < datetime_convert('UTC','UTC','now - 1 month')) {
|
||||
self::update($outq['outq_hash'], 10);
|
||||
logger('immediate delivery deferred for site ' . $base);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -202,7 +232,7 @@ class Queue {
|
||||
|
||||
if($channel && $base) {
|
||||
$h = q("SELECT hubloc_sitekey, site_crypto FROM hubloc LEFT JOIN site ON hubloc_url = site_url
|
||||
WHERE site_url = '%s' AND hubloc_network = 'zot6' ORDER BY hubloc_id DESC LIMIT 1",
|
||||
WHERE site_url = '%s' AND hubloc_network = 'zot6' AND hubloc_deleted = 0 ORDER BY hubloc_primary DESC, hubloc_id DESC LIMIT 1",
|
||||
dbesc($base)
|
||||
);
|
||||
if($h) {
|
||||
@@ -216,7 +246,7 @@ class Queue {
|
||||
|
||||
if($result['success']) {
|
||||
logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']);
|
||||
Libzot::process_response($outq['outq_posturl'],$result, $outq);
|
||||
Libzot::process_response($outq['outq_posturl'], $result, $outq);
|
||||
}
|
||||
else {
|
||||
logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']);
|
||||
|
||||
375
Zotlabs/Lib/QueueWorker.php
Normal file
375
Zotlabs/Lib/QueueWorker.php
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once 'include/dba/dba_transaction.php';
|
||||
|
||||
class QueueWorker {
|
||||
|
||||
public static $queueworker = null;
|
||||
public static $maxworkers = 0;
|
||||
public static $workermaxage = 0;
|
||||
public static $workersleep = 100;
|
||||
public static $default_priorities = [
|
||||
'Notifier' => 10,
|
||||
'Deliver' => 10,
|
||||
'Cache_query' => 10,
|
||||
'Content_importer' => 1,
|
||||
'File_importer' => 1,
|
||||
'Channel_purge' => 1,
|
||||
'Directory' => 1
|
||||
];
|
||||
|
||||
// Exceptions for processtimeout ($workermaxage) value.
|
||||
// Currently the value is overriden with 3600 seconds (1h).
|
||||
public static $long_running_cmd = [
|
||||
'Queue',
|
||||
'Expire'
|
||||
];
|
||||
|
||||
public static function Summon($argv) {
|
||||
|
||||
if ($argv[0] !== 'Queueworker') {
|
||||
|
||||
$priority = 0; // @TODO allow reprioritization
|
||||
|
||||
if (isset(self::$default_priorities[$argv[0]])) {
|
||||
$priority = self::$default_priorities[$argv[0]];
|
||||
}
|
||||
|
||||
$workinfo = ['argc' => count($argv), 'argv' => $argv];
|
||||
$workinfo_json = json_encode($workinfo);
|
||||
$uuid = self::getUuid($workinfo_json);
|
||||
|
||||
$r = q("SELECT * FROM workerq WHERE workerq_uuid = '%s'",
|
||||
dbesc($uuid)
|
||||
);
|
||||
if ($r) {
|
||||
logger("Summon: Ignoring duplicate workerq task", LOGGER_DEBUG);
|
||||
logger(print_r($workinfo, true));
|
||||
return;
|
||||
}
|
||||
|
||||
logger('queueworker_stats_summon: cmd:' . $argv[0] . ' ' . 'timestamp:' . time());
|
||||
|
||||
$transaction = new \DbaTransaction(\DBA::$dba);
|
||||
$r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')",
|
||||
intval($priority),
|
||||
dbesc($workinfo_json),
|
||||
dbesc($uuid),
|
||||
dbesc($argv[0])
|
||||
);
|
||||
if (!$r) {
|
||||
// Transaction is autmatically rolled back on return
|
||||
logger("INSERT FAILED", LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
$transaction->commit();
|
||||
logger('INSERTED: ' . $workinfo_json, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
$workers = self::GetWorkerCount();
|
||||
if ($workers < self::$maxworkers) {
|
||||
logger($workers . '/' . self::$maxworkers . ' workers active', LOGGER_DEBUG);
|
||||
$phpbin = Config::Get('system', 'phpbin', 'php');
|
||||
proc_run($phpbin, 'Zotlabs/Daemon/Master.php', ['Queueworker']);
|
||||
}
|
||||
}
|
||||
|
||||
public static function Release($argv) {
|
||||
|
||||
if ($argv[0] !== 'Queueworker') {
|
||||
|
||||
$priority = 0; // @TODO allow reprioritization
|
||||
if (isset(self::$default_priorities[$argv[0]])) {
|
||||
$priority = self::$default_priorities[$argv[0]];
|
||||
}
|
||||
|
||||
$workinfo = ['argc' => count($argv), 'argv' => $argv];
|
||||
$workinfo_json = json_encode($workinfo);
|
||||
$uuid = self::getUuid($workinfo_json);
|
||||
|
||||
$r = q("SELECT * FROM workerq WHERE workerq_uuid = '%s'",
|
||||
dbesc($uuid)
|
||||
);
|
||||
if ($r) {
|
||||
logger("Release: Duplicate task - do not insert.", LOGGER_DEBUG);
|
||||
logger(print_r($workinfo, true));
|
||||
return;
|
||||
}
|
||||
|
||||
$transaction = new \DbaTransaction(\DBA::$dba);
|
||||
$r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')",
|
||||
intval($priority),
|
||||
dbesc($workinfo_json),
|
||||
dbesc($uuid),
|
||||
dbesc($argv[0])
|
||||
);
|
||||
if (!$r) {
|
||||
// Transaction is automatically rolled back on return
|
||||
logger("Insert failed: " . $workinfo_json, LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
$transaction->commit();
|
||||
logger('INSERTED: ' . $workinfo_json, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
self::Process();
|
||||
}
|
||||
|
||||
public static function GetWorkerCount() {
|
||||
if (self::$maxworkers == 0) {
|
||||
self::$maxworkers = Config::Get('queueworker', 'max_queueworkers', 4);
|
||||
self::$maxworkers = self::$maxworkers > 3 ? self::$maxworkers : 4;
|
||||
}
|
||||
if (self::$workermaxage == 0) {
|
||||
self::$workermaxage = Config::Get('queueworker', 'max_queueworker_age');
|
||||
self::$workermaxage = self::$workermaxage > 120 ? self::$workermaxage : 300;
|
||||
}
|
||||
|
||||
$transaction = new \DbaTransaction(\DBA::$dba);
|
||||
|
||||
// skip locked is preferred but is not supported by mariadb < 10.6 which is still used a lot - hence make it optional
|
||||
$sql_quirks = ((Config::Get('system', 'db_skip_locked_supported')) ? 'SKIP LOCKED' : 'NOWAIT');
|
||||
|
||||
$r = q("SELECT workerq_id FROM workerq WHERE workerq_reservationid IS NOT NULL AND workerq_processtimeout < %s FOR UPDATE $sql_quirks",
|
||||
db_utcnow()
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
// TODO: some long running services store their pid in config.procid.daemon
|
||||
// we could possibly check if a pid exist and check if the process is still alive
|
||||
// prior to reseting workerq_reservationid
|
||||
|
||||
$ids = ids_to_querystr($r, 'workerq_id');
|
||||
$u = dbq("update workerq set workerq_reservationid = null where workerq_id in ($ids)");
|
||||
}
|
||||
|
||||
$transaction->commit();
|
||||
|
||||
//q("update workerq set workerq_reservationid = null where workerq_reservationid is not null and workerq_processtimeout < %s",
|
||||
//db_utcnow()
|
||||
//);
|
||||
|
||||
//usleep(self::$workersleep);
|
||||
|
||||
$workers = dbq("select count(*) as total from workerq where workerq_reservationid is not null");
|
||||
logger("WORKERCOUNT: " . $workers[0]['total'], LOGGER_DEBUG);
|
||||
|
||||
return intval($workers[0]['total']);
|
||||
}
|
||||
|
||||
public static function GetWorkerID() {
|
||||
if (self::$queueworker) {
|
||||
return self::$queueworker;
|
||||
}
|
||||
|
||||
$wid = uniqid('', true);
|
||||
|
||||
//usleep(mt_rand(300000, 1000000)); //Sleep .3 - 1 seconds before creating a new worker.
|
||||
|
||||
$workers = self::GetWorkerCount();
|
||||
|
||||
if ($workers >= self::$maxworkers) {
|
||||
logger("Too many active workers ($workers) max = " . self::$maxworkers, LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$queueworker = $wid;
|
||||
|
||||
return $wid;
|
||||
}
|
||||
|
||||
private static function getWorkId() {
|
||||
self::GetWorkerCount();
|
||||
|
||||
$transaction = new \DbaTransaction(\DBA::$dba);
|
||||
|
||||
// skip locked is preferred but is not supported by mariadb < 10.6 which is still used a lot - hence make it optional
|
||||
$sql_quirks = ((Config::Get('system', 'db_skip_locked_supported')) ? 'SKIP LOCKED' : 'NOWAIT');
|
||||
|
||||
$work = dbq("SELECT workerq_id, workerq_cmd FROM workerq WHERE workerq_reservationid IS NULL ORDER BY workerq_priority DESC, workerq_id ASC LIMIT 1 FOR UPDATE $sql_quirks");
|
||||
|
||||
if (!$work) {
|
||||
// Transaction automatically rolled back on return
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $work[0]['workerq_id'];
|
||||
$cmd = $work[0]['workerq_cmd'];
|
||||
$age = self::$workermaxage;
|
||||
|
||||
if (in_array($cmd, self::$long_running_cmd)) {
|
||||
$age = 3600; // 1h TODO: make this configurable
|
||||
}
|
||||
|
||||
$work = q("UPDATE workerq SET workerq_reservationid = '%s', workerq_processtimeout = %s + INTERVAL %s WHERE workerq_id = %d",
|
||||
self::$queueworker,
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . " SECOND"),
|
||||
intval($id)
|
||||
);
|
||||
|
||||
if (!$work) {
|
||||
// Transaction automatically rolled back on return
|
||||
logger("Could not update workerq.", LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
logger("GOTWORK: " . json_encode($work), LOGGER_DEBUG);
|
||||
$transaction->commit();
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public static function Process() {
|
||||
$sleep = intval(Config::Get('queueworker', 'queue_worker_sleep', 100));
|
||||
$auto_queue_worker_sleep = Config::Get('queueworker', 'auto_queue_worker_sleep', 0);
|
||||
|
||||
if (!self::GetWorkerID()) {
|
||||
if ($auto_queue_worker_sleep) {
|
||||
Config::Set('queueworker', 'queue_worker_sleep', $sleep + 100);
|
||||
}
|
||||
|
||||
logger('Unable to get worker ID. Exiting.', LOGGER_DEBUG);
|
||||
killme();
|
||||
}
|
||||
|
||||
if ($auto_queue_worker_sleep && $sleep > 100) {
|
||||
$next_sleep = $sleep - 100;
|
||||
Config::Set('queueworker', 'queue_worker_sleep', (($next_sleep < 100) ? 100 : $next_sleep));
|
||||
}
|
||||
|
||||
$jobs = 0;
|
||||
$workid = self::getWorkId();
|
||||
$load_average_sleep = false;
|
||||
self::$workersleep = $sleep;
|
||||
self::$workersleep = ((intval(self::$workersleep) > 100) ? intval(self::$workersleep) : 100);
|
||||
|
||||
if (function_exists('sys_getloadavg') && Config::Get('queueworker', 'load_average_sleep')) {
|
||||
// very experimental!
|
||||
$load_average_sleep = true;
|
||||
}
|
||||
|
||||
while ($workid) {
|
||||
|
||||
if ($load_average_sleep) {
|
||||
$load_average = sys_getloadavg();
|
||||
self::$workersleep = intval($load_average[0]) * 10000;
|
||||
|
||||
if (!self::$workersleep) {
|
||||
self::$workersleep = 100;
|
||||
}
|
||||
}
|
||||
|
||||
logger('queue_worker_sleep: ' . self::$workersleep, LOGGER_DEBUG);
|
||||
|
||||
usleep(self::$workersleep);
|
||||
|
||||
$workitem = dbq("SELECT * FROM workerq WHERE workerq_id = $workid");
|
||||
|
||||
if ($workitem) {
|
||||
// At least SOME work to do.... in case there's more, let's ramp up workers.
|
||||
$workers = self::GetWorkerCount();
|
||||
|
||||
if ($workers < self::$maxworkers) {
|
||||
logger($workers . '/' . self::$maxworkers . ' workers active', LOGGER_DEBUG);
|
||||
$phpbin = Config::Get('system', 'phpbin', 'php');
|
||||
proc_run($phpbin, 'Zotlabs/Daemon/Master.php', ['Queueworker']);
|
||||
}
|
||||
|
||||
$jobs++;
|
||||
|
||||
logger("Workinfo: " . $workitem[0]['workerq_data'], LOGGER_DEBUG);
|
||||
|
||||
$workinfo = json_decode($workitem[0]['workerq_data'], true);
|
||||
$argv = $workinfo['argv'];
|
||||
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$argv = flatten_array_recursive($argv);
|
||||
$argc = count($argv);
|
||||
$rnd = random_string(16);
|
||||
|
||||
logger('PROCESSING: ' . $rnd . ' ' . print_r($argv[0], true));
|
||||
|
||||
$start_timestamp = microtime(true);
|
||||
|
||||
$cls::run($argc, $argv);
|
||||
|
||||
logger('logger_stats_data cmd:' . $argv[0] . ' start:' . $start_timestamp . ' ' . 'end:' . microtime(true) . ' meta:' . $rnd);
|
||||
|
||||
logger('COMPLETED: ' . $rnd);
|
||||
|
||||
// @FIXME: Right now we assume that if we get a return, everything is OK.
|
||||
// At some point we may want to test whether the run returns true/false
|
||||
// and requeue the work to be tried again if needed. But we probably want
|
||||
// to implement some sort of "retry interval" first.
|
||||
|
||||
dbq("delete from workerq where workerq_id = $workid");
|
||||
}
|
||||
else {
|
||||
logger("NO WORKITEM!", LOGGER_DEBUG);
|
||||
}
|
||||
$workid = self::getWorkId();
|
||||
}
|
||||
logger('Master: Worker Thread: queue items processed:' . $jobs, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
public static function ClearQueue() {
|
||||
$work = q("select * from workerq");
|
||||
while ($work) {
|
||||
foreach ($work as $workitem) {
|
||||
$workinfo = json_decode($workitem['v'], true);
|
||||
$argc = $workinfo['argc'];
|
||||
$argv = $workinfo['argv'];
|
||||
|
||||
logger('Master: process: ' . print_r($argv, true), LOGGER_ALL, LOG_DEBUG);
|
||||
|
||||
if (!isset($argv[0])) {
|
||||
q("delete from workerq where workerq_id = %d",
|
||||
$work[0]['workerq_id']
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$cls::run($argc, $argv);
|
||||
|
||||
q("delete from workerq where workerq_id = %d",
|
||||
$work[0]['workerq_id']
|
||||
);
|
||||
|
||||
//Give the server .3 seconds to catch its breath between tasks.
|
||||
//This will hopefully keep it from crashing to it's knees entirely
|
||||
//if the last task ended up initiating other parallel processes
|
||||
//(eg. polling remotes)
|
||||
usleep(300000);
|
||||
}
|
||||
|
||||
//Make sure nothing new came in
|
||||
$work = q("select * from workerq");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate a name-based v5 UUID with custom namespace
|
||||
*
|
||||
* @param string $data
|
||||
* @return string $uuid
|
||||
*/
|
||||
private static function getUuid(string $data) {
|
||||
$namespace = '3a112e42-f147-4ccf-a78b-f6841339ea2a';
|
||||
try {
|
||||
$uuid = Uuid::uuid5($namespace, $data)->toString();
|
||||
} catch (UnableToBuildUuidException $e) {
|
||||
logger('UUID generation failed');
|
||||
return '';
|
||||
}
|
||||
return $uuid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -112,7 +112,7 @@ class Share {
|
||||
if(! $this->item)
|
||||
return $bb;
|
||||
|
||||
$is_photo = (($this->item['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false);
|
||||
$is_photo = ((in_array($this->item['obj_type'], ['Image', ACTIVITY_OBJ_PHOTO])) ? true : false);
|
||||
if($is_photo) {
|
||||
$object = json_decode($this->item['obj'],true);
|
||||
$photo_bb = $object['body'];
|
||||
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -16,13 +16,13 @@ class System {
|
||||
}
|
||||
|
||||
static public function get_site_name() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['sitename'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['sitename']))
|
||||
return \App::$config['system']['sitename'];
|
||||
return '';
|
||||
}
|
||||
|
||||
static public function get_project_version() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['hide_version'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['hide_version']))
|
||||
return '';
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('std_version',\App::$config['system']))
|
||||
return \App::$config['system']['std_version'];
|
||||
@@ -31,33 +31,33 @@ class System {
|
||||
}
|
||||
|
||||
static public function get_update_version() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['hide_version'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['hide_version']))
|
||||
return '';
|
||||
return DB_UPDATE_VERSION;
|
||||
}
|
||||
|
||||
|
||||
static public function get_notify_icon() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['email_notify_icon_url'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['email_notify_icon_url']))
|
||||
return \App::$config['system']['email_notify_icon_url'];
|
||||
return z_root() . DEFAULT_NOTIFY_ICON;
|
||||
}
|
||||
|
||||
static public function get_site_icon() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['site_icon_url'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['site_icon_url']))
|
||||
return \App::$config['system']['site_icon_url'];
|
||||
return z_root() . DEFAULT_PLATFORM_ICON ;
|
||||
}
|
||||
|
||||
|
||||
static public function get_project_link() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['project_link'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['project_link']))
|
||||
return \App::$config['system']['project_link'];
|
||||
return 'https://hubzilla.org';
|
||||
}
|
||||
|
||||
static public function get_project_srclink() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['project_srclink'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['project_srclink']))
|
||||
return \App::$config['system']['project_srclink'];
|
||||
return 'https://framagit.org/hubzilla/core.git';
|
||||
}
|
||||
@@ -68,7 +68,7 @@ class System {
|
||||
|
||||
|
||||
static public function get_zot_revision() {
|
||||
$x = [ 'revision' => ZOT_REVISION ];
|
||||
$x = [ 'revision' => ZOT_REVISION ];
|
||||
call_hooks('zot_revision',$x);
|
||||
return $x['revision'];
|
||||
}
|
||||
|
||||
24
Zotlabs/Lib/Text.php
Normal file
24
Zotlabs/Lib/Text.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
class Text {
|
||||
|
||||
/**
|
||||
* use this on "body" or "content" input where angle chars shouldn't be removed,
|
||||
* and allow them to be safely displayed.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
public static function escape_tags(string $string): string {
|
||||
if (!$string) {
|
||||
return EMPTY_STR;
|
||||
}
|
||||
|
||||
return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,8 +3,9 @@
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Access\AccessList;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Config;
|
||||
|
||||
require_once('include/text.php');
|
||||
|
||||
@@ -19,7 +20,7 @@ class ThreadItem {
|
||||
private $comment_box_template = 'comment_item.tpl';
|
||||
private $commentable = false;
|
||||
// list of supported reaction emojis - a site can over-ride this via config system.reactions
|
||||
private $reactions = ['1f60a','1f44f','1f37e','1f48b','1f61e','2665','1f606','1f62e','1f634','1f61c','1f607','1f608'];
|
||||
private $reactions = ['slightly_smiling_face','clapping_hands','bottle_with_popping_cork','kiss_mark','disappointed_face','red_heart','grinning_face','astonished_face','sleeping_face','winking_face_with_tongue','smiling_face_with_halo','smiling_face_with_horns'];
|
||||
private $toplevel = false;
|
||||
private $children = array();
|
||||
private $parent = null;
|
||||
@@ -34,18 +35,18 @@ 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 = get_config('system','thread_allow');
|
||||
|
||||
$observer = \App::get_observer();
|
||||
$this->threaded = Config::Get('system','thread_allow');
|
||||
|
||||
// Prepare the children
|
||||
if(isset($data['children'])) {
|
||||
|
||||
foreach($data['children'] as $item) {
|
||||
|
||||
/*
|
||||
@@ -56,7 +57,6 @@ class ThreadItem {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$child = new ThreadItem($item);
|
||||
$this->add_child($child);
|
||||
}
|
||||
@@ -65,9 +65,11 @@ class ThreadItem {
|
||||
unset($this->data['children']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// allow a site to configure the order and content of the reaction emoji list
|
||||
if($this->toplevel) {
|
||||
$x = get_config('system','reactions');
|
||||
$x = Config::Get('system','reactions');
|
||||
if($x && is_array($x) && count($x)) {
|
||||
$this->reactions = $x;
|
||||
}
|
||||
@@ -82,28 +84,26 @@ class ThreadItem {
|
||||
* _ false on failure
|
||||
*/
|
||||
|
||||
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
|
||||
|
||||
$result = array();
|
||||
|
||||
$item = $this->get_data();
|
||||
public function get_template_data($conv_responses, $mid_uuid_map, $thread_level=1, $conv_flags = []) {
|
||||
|
||||
$result = [];
|
||||
$item = $this->get_data();
|
||||
$commentww = '';
|
||||
$sparkle = '';
|
||||
$buttons = '';
|
||||
$dropping = false;
|
||||
$star = false;
|
||||
$isstarred = "unstarred fa-star-o";
|
||||
$isstarred = "unstarred bi-star";
|
||||
$is_comment = false;
|
||||
$is_item = false;
|
||||
$osparkle = '';
|
||||
$total_children = $this->count_descendants();
|
||||
$unseen_comments = (($item['real_uid']) ? 0 : $this->count_unseen_descendants());
|
||||
$unseen_comments = ((isset($item['real_uid']) && $item['real_uid']) ? 0 : $this->count_unseen_descendants());
|
||||
|
||||
$conv = $this->get_conversation();
|
||||
$observer = $conv->get_observer();
|
||||
|
||||
$acl = new AccessList(false);
|
||||
$acl = new AccessList([]);
|
||||
$acl->set($item);
|
||||
|
||||
$lock = ((intval($item['item_private']) || ($item['uid'] == local_channel() && $acl->is_private()))
|
||||
@@ -123,12 +123,14 @@ class ThreadItem {
|
||||
$locktype = 0;
|
||||
}
|
||||
|
||||
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false);
|
||||
$shareable = ((local_channel() && $conv->get_profile_owner() == local_channel()) && (intval($item['item_private']) === 0));
|
||||
|
||||
// allow an exemption for sharing stuff from your private feeds
|
||||
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']));
|
||||
|
||||
// @fixme
|
||||
// Have recently added code to properly handle polls in group reshares by redirecting all of the poll responses to the group.
|
||||
// Sharing a poll using a regular embedded share is harder because the poll will need to fork. This is due to comment permissions.
|
||||
@@ -139,16 +141,10 @@ class ThreadItem {
|
||||
$shareable = false;
|
||||
}
|
||||
|
||||
$privacy_warning = false;
|
||||
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
|
||||
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
|
||||
|
||||
if(! is_array($recips['to']) || ! in_array($observer['xchan_url'], $recips['to']))
|
||||
$privacy_warning = true;
|
||||
}
|
||||
$privacy_warning = ($item['owner']['xchan_network'] === 'activitypub' && intval($item['item_private']) === 1);
|
||||
|
||||
if ($lock) {
|
||||
if (($item['mid'] == $item['parent_mid']) && count(get_terms_oftype($item['term'],TERM_FORUM))) {
|
||||
if (($item['mid'] == $item['parent_mid']) && isset($item['term']) && count(get_terms_oftype($item['term'], TERM_FORUM))) {
|
||||
$privacy_warning = true;
|
||||
$conv_flags['parent_privacy_warning'] = true;
|
||||
}
|
||||
@@ -162,24 +158,11 @@ class ThreadItem {
|
||||
|
||||
$mode = $conv->get_mode();
|
||||
|
||||
switch($item['item_type']) {
|
||||
case ITEM_TYPE_CARD:
|
||||
$edlink = 'card_edit';
|
||||
break;
|
||||
case ITEM_TYPE_ARTICLE:
|
||||
$edlink = 'article_edit';
|
||||
break;
|
||||
default:
|
||||
$edlink = 'editpost';
|
||||
break;
|
||||
}
|
||||
|
||||
if(local_channel() && $observer['xchan_hash'] === $item['author_xchan'])
|
||||
$edpost = array(z_root() . '/' . $edlink . '/' . $item['id'], t('Edit'));
|
||||
$edpost = array(z_root() . '/editpost/' . $item['id'], t('Edit'));
|
||||
else
|
||||
$edpost = false;
|
||||
|
||||
|
||||
if($observer && $observer['xchan_hash']
|
||||
&& ($observer['xchan_hash'] == $this->get_data_value('author_xchan')
|
||||
|| $observer['xchan_hash'] == $this->get_data_value('owner_xchan')
|
||||
@@ -193,7 +176,7 @@ class ThreadItem {
|
||||
$dropping = false;
|
||||
}
|
||||
|
||||
|
||||
$drop = [];
|
||||
if($dropping) {
|
||||
$drop = array(
|
||||
'dropping' => $dropping,
|
||||
@@ -204,29 +187,28 @@ class ThreadItem {
|
||||
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
|
||||
}
|
||||
|
||||
// FIXME
|
||||
if($observer_is_pageowner) {
|
||||
$multidrop = array(
|
||||
'select' => t('Select'),
|
||||
);
|
||||
}
|
||||
$filer = (((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) ? t("Save to Folder") : false);
|
||||
|
||||
$filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) ? t("Save to Folder") : false);
|
||||
|
||||
$profile_avatar = $item['author']['xchan_photo_m'];
|
||||
$profile_avatar = $item['author']['xchan_photo_s'];
|
||||
$profile_link = chanlink_hash($item['author_xchan']);
|
||||
$profile_name = $item['author']['xchan_name'];
|
||||
|
||||
$location = format_location($item);
|
||||
$isevent = false;
|
||||
$attend = null;
|
||||
$canvote = false;
|
||||
|
||||
// process action responses - e.g. like/dislike/attend/agree/whatever
|
||||
$response_verbs = array('like');
|
||||
if(feature_enabled($conv->get_profile_owner(),'dislike'))
|
||||
$response_verbs[] = 'like';
|
||||
|
||||
if(feature_enabled($conv->get_profile_owner(),'dislike')) {
|
||||
$response_verbs[] = 'dislike';
|
||||
if($item['obj_type'] === ACTIVITY_OBJ_EVENT) {
|
||||
}
|
||||
|
||||
if ($repeatable) {
|
||||
$response_verbs[] = 'announce';
|
||||
}
|
||||
|
||||
if (in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
|
||||
$response_verbs[] = 'attendyes';
|
||||
$response_verbs[] = 'attendno';
|
||||
$response_verbs[] = 'attendmaybe';
|
||||
@@ -236,56 +218,21 @@ class ThreadItem {
|
||||
}
|
||||
}
|
||||
|
||||
if($item['obj_type'] === 'Question') {
|
||||
if ($item['obj_type'] === 'Question') {
|
||||
$response_verbs[] = 'answer';
|
||||
}
|
||||
|
||||
$consensus = (intval($item['item_consensus']) ? true : false);
|
||||
if($consensus) {
|
||||
$response_verbs[] = 'agree';
|
||||
$response_verbs[] = 'disagree';
|
||||
$response_verbs[] = 'abstain';
|
||||
if($this->is_commentable() && $observer) {
|
||||
$conlabels = array( t('I agree'), t('I disagree'), t('I abstain'));
|
||||
$canvote = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(! feature_enabled($conv->get_profile_owner(),'dislike'))
|
||||
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] = (($conv_responses[$v][$item['mid'] . '-m']) ? 1 : 0);
|
||||
$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');
|
||||
|
||||
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 = '';
|
||||
}
|
||||
}
|
||||
|
||||
$showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : '');
|
||||
$showdislike = ((x($conv_responses['dislike'],$item['mid']) && feature_enabled($conv->get_profile_owner(),'dislike'))
|
||||
? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : '');
|
||||
|
||||
/*
|
||||
* We should avoid doing this all the time, but it depends on the conversation mode
|
||||
@@ -296,14 +243,11 @@ class ThreadItem {
|
||||
$this->check_wall_to_wall();
|
||||
|
||||
if($this->is_toplevel()) {
|
||||
// FIXME check this permission
|
||||
if(($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) {
|
||||
|
||||
$star = array(
|
||||
if((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) {
|
||||
$star = [
|
||||
'toggle' => t("Toggle Star Status"),
|
||||
'isstarred' => ((intval($item['item_starred'])) ? true : false),
|
||||
);
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -320,7 +264,7 @@ class ThreadItem {
|
||||
$tagger = [];
|
||||
|
||||
// FIXME - check this permission
|
||||
if($conv->get_profile_owner() == local_channel()) {
|
||||
if(local_channel() && $conv->get_profile_owner() == local_channel()) {
|
||||
/* disable until we agree on how to implemnt this in zot6/activitypub
|
||||
$tagger = array(
|
||||
'tagit' => t("Add Tag"),
|
||||
@@ -332,7 +276,7 @@ class ThreadItem {
|
||||
}
|
||||
|
||||
$has_bookmarks = false;
|
||||
if(Apps::system_app_installed(local_channel(), 'Bookmarks') && is_array($item['term'])) {
|
||||
if(Apps::system_app_installed(local_channel(), 'Bookmarks') && isset($item['term']) && is_array($item['term'])) {
|
||||
foreach($item['term'] as $t) {
|
||||
if(($t['ttype'] == TERM_BOOKMARK))
|
||||
$has_bookmarks = true;
|
||||
@@ -340,42 +284,51 @@ class ThreadItem {
|
||||
}
|
||||
|
||||
$has_event = false;
|
||||
if(($item['obj_type'] === ACTIVITY_OBJ_EVENT) && $conv->get_profile_owner() == local_channel())
|
||||
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 on this comment"), t("reply"), t("Reply to"));
|
||||
$reply_to = array( t("Reply to this comment"), t("reply"), t("Reply to"));
|
||||
$reactions_allowed = true;
|
||||
}
|
||||
|
||||
$share = [];
|
||||
$embed = [];
|
||||
if ($shareable) {
|
||||
// This actually turns out not to be possible in some protocol stacks without opening up hundreds of new issues.
|
||||
// Will allow it only for uri resolvable sources.
|
||||
if(strpos($item['mid'],'http') === 0) {
|
||||
$share = []; //Not yet ready for primetime
|
||||
//$share = array( t('Repeat This'), t('repeat'));
|
||||
}
|
||||
$embed = array( t('Share This'), t('share'));
|
||||
$embed = [t('Share'), t('share')];
|
||||
}
|
||||
|
||||
if ($repeatable) {
|
||||
$share = [t('Repeat'), t('repeat')];
|
||||
}
|
||||
|
||||
$dreport = '';
|
||||
|
||||
$keep_reports = intval(get_config('system','expire_delivery_reports'));
|
||||
$keep_reports = intval(Config::Get('system','expire_delivery_reports'));
|
||||
if($keep_reports === 0)
|
||||
$keep_reports = 10;
|
||||
|
||||
if((! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) {
|
||||
$dreport_link = '';
|
||||
if((intval($item['item_type']) == ITEM_TYPE_POST) && (! Config::Get('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) {
|
||||
$dreport = t('Delivery Report');
|
||||
$dreport_link = gen_link_id($item['mid']);
|
||||
$dreport_link = '?mid=' . $item['mid'];
|
||||
}
|
||||
|
||||
$is_new = false;
|
||||
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
|
||||
$is_new = true;
|
||||
|
||||
localize_item($item);
|
||||
|
||||
$body = prepare_body($item,true);
|
||||
$opts = (($item['resource_type'] === 'event') ? ['is_event_item' => true] : []);
|
||||
$body = prepare_body($item, true, $opts);
|
||||
|
||||
// $viewthread (below) is only valid in list mode. If this is a channel page, build the thread viewing link
|
||||
// since we can't depend on llink or plink pointing to the right local location.
|
||||
@@ -385,8 +338,8 @@ class ThreadItem {
|
||||
if($conv->get_mode() === 'channel')
|
||||
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
|
||||
|
||||
$comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children );
|
||||
$list_unseen_txt = (($unseen_comments) ? sprintf( t('%d unseen'),$unseen_comments) : '');
|
||||
$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();
|
||||
|
||||
@@ -396,8 +349,8 @@ class ThreadItem {
|
||||
call_hooks('dropdown_extras',$dropdown_extras_arr);
|
||||
$dropdown_extras = $dropdown_extras_arr['dropdown_extras'];
|
||||
|
||||
$midb64 = gen_link_id($item['mid']);
|
||||
$mids = [ $midb64 ];
|
||||
$midb64 = $item['uuid'];
|
||||
$mids = [ $item['uuid'] ];
|
||||
$response_mids = [];
|
||||
foreach($response_verbs as $v) {
|
||||
if(isset($conv_responses[$v]['mids'][$item['mid']])) {
|
||||
@@ -409,7 +362,7 @@ class ThreadItem {
|
||||
$json_mids = json_encode($mids);
|
||||
|
||||
// Pinned item processing
|
||||
$allowed_type = (in_array($item['item_type'], get_config('system', 'pin_types', [ ITEM_TYPE_POST ])) ? true : false);
|
||||
$allowed_type = (in_array($item['item_type'], Config::Get('system', 'pin_types', [ ITEM_TYPE_POST ])) ? true : false);
|
||||
$pinned_items = ($allowed_type ? get_pconfig($item['uid'], 'pinned', $item['item_type'], []) : []);
|
||||
$pinned = ((!empty($pinned_items) && in_array($midb64, $pinned_items)) ? true : false);
|
||||
|
||||
@@ -423,7 +376,6 @@ class ThreadItem {
|
||||
'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'],
|
||||
@@ -439,9 +391,6 @@ class ThreadItem {
|
||||
'author_is_group_actor' => (($item['author']['xchan_pubforum']) ? t('Forum') : ''),
|
||||
'isevent' => $isevent,
|
||||
'attend' => $attend,
|
||||
'consensus' => $consensus,
|
||||
'conlabels' => $conlabels,
|
||||
'canvote' => $canvote,
|
||||
'linktitle' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
||||
'olinktitle' => (($item['owner']['xchan_addr']) ? $item['owner']['xchan_addr'] : $item['owner']['xchan_url']),
|
||||
'llink' => $item['llink'],
|
||||
@@ -461,16 +410,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'] > 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,
|
||||
@@ -490,7 +438,7 @@ 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 : ''),
|
||||
@@ -500,7 +448,7 @@ class ThreadItem {
|
||||
'embed' => $embed,
|
||||
'rawmid' => $item['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 : ''),
|
||||
@@ -510,38 +458,32 @@ class ThreadItem {
|
||||
'bookmark' => (($conv->get_profile_owner() == local_channel() && local_channel() && $has_bookmarks) ? t('Save Bookmarks') : ''),
|
||||
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
|
||||
'drop' => $drop,
|
||||
'multidrop' => ((feature_enabled($conv->get_profile_owner(),'multi_delete')) ? $multidrop : ''),
|
||||
'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 seen'),
|
||||
'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'),
|
||||
'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 : ''),
|
||||
'modal_dismiss' => t('Close'),
|
||||
'showlike' => $showlike,
|
||||
'showdislike' => $showdislike,
|
||||
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box($indent)),
|
||||
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()),
|
||||
'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' => (($item['parent_mid'] != $item['thr_parent']) ? gen_link_id($item['thr_parent']) : ''),
|
||||
'contact_id' => (($contact) ? $contact['abook_id'] : '')
|
||||
|
||||
'thr_parent_uuid' => (($item['parent_mid'] != $item['thr_parent']) ? $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')],
|
||||
'is_contained' => $this->is_toplevel() && str_contains($item['tgt_type'], 'Collection')
|
||||
);
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
@@ -552,25 +494,17 @@ class ThreadItem {
|
||||
$result['children'] = array();
|
||||
$nb_children = count($children);
|
||||
|
||||
$visible_comments = get_config('system','expanded_comments');
|
||||
if($visible_comments === false)
|
||||
$visible_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;
|
||||
$visible_comments = Config::Get('system', 'expanded_comments', 3);
|
||||
|
||||
if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
|
||||
foreach($children as $child) {
|
||||
$result['children'][] = $child->get_template_data($conv_responses, $thread_level + 1,$conv_flags);
|
||||
$result['children'][] = $child->get_template_data($conv_responses, $mid_uuid_map, $thread_level + 1,$conv_flags);
|
||||
}
|
||||
// Collapse
|
||||
if(($nb_children > $visible_comments) || ($thread_level > 1)) {
|
||||
$result['children'][0]['comment_firstcollapsed'] = true;
|
||||
$result['children'][0]['num_comments'] = $comment_count_txt;
|
||||
$result['children'][0]['hide_text'] = sprintf( t('%s show all'), '<i class="fa fa-chevron-down"></i>');
|
||||
$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;
|
||||
}
|
||||
@@ -646,7 +580,7 @@ class ThreadItem {
|
||||
* Only add what will be displayed
|
||||
*/
|
||||
|
||||
if(activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE)) {
|
||||
if(activity_match($item->get_data_value('verb'), ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -827,9 +761,9 @@ class ThreadItem {
|
||||
* _ The comment box string (empty if no comment box)
|
||||
* _ false on failure
|
||||
*/
|
||||
private function get_comment_box($indent) {
|
||||
private function get_comment_box() {
|
||||
|
||||
if(!$this->is_toplevel() && !get_config('system','thread_allow')) {
|
||||
if(!$this->is_toplevel() && !Config::Get('system','thread_allow')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -872,13 +806,12 @@ class ThreadItem {
|
||||
'$edatt' => t('Attach/Upload file'),
|
||||
'$edurl' => t('Insert Link'),
|
||||
'$edvideo' => t('Video'),
|
||||
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
|
||||
'$indent' => $indent,
|
||||
'$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'),
|
||||
'$cipher' => $conv->get_cipher(),
|
||||
'$sourceapp' => \App::$sourcename,
|
||||
'$sourceapp' => App::$sourcename,
|
||||
'$observer' => get_observer_hash(),
|
||||
'$anoncomments' => ((in_array($conv->get_mode(), ['channel', 'display', 'cards', 'articles']) && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
|
||||
'$anonname' => [ 'anonname', t('Your full name (required)') ],
|
||||
@@ -894,7 +827,7 @@ 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();
|
||||
@@ -908,10 +841,16 @@ 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_photo = $this->data['owner']['xchan_photo_m'];
|
||||
$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_photo = $this->data['source']['xchan_photo_s'];
|
||||
$this->owner_name = $this->data['source']['xchan_name'];
|
||||
$this->wall_to_wall = true;
|
||||
}
|
||||
}
|
||||
|
||||
private function is_wall_to_wall() {
|
||||
|
||||
@@ -4,18 +4,30 @@ namespace Zotlabs\Lib;
|
||||
|
||||
class ThreadListener {
|
||||
|
||||
public static function isEnabled() {
|
||||
return Config::Get('system','enable_thread_listener');
|
||||
}
|
||||
|
||||
static public function store($target_id,$portable_id,$ltype = 0) {
|
||||
if (!self::isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$x = self::fetch($target_id,$portable_id,$ltype = 0);
|
||||
if(! $x) {
|
||||
if(! $x) {
|
||||
$r = q("insert into listeners ( target_id, portable_id, ltype ) values ( '%s', '%s' , %d ) ",
|
||||
dbesc($target_id),
|
||||
dbesc($portable_id),
|
||||
intval($ltype)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public function fetch($target_id,$portable_id,$ltype = 0) {
|
||||
if (!self::isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$x = q("select * from listeners where target_id = '%s' and portable_id = '%s' and ltype = %d limit 1",
|
||||
dbesc($target_id),
|
||||
dbesc($portable_id),
|
||||
@@ -28,6 +40,10 @@ class ThreadListener {
|
||||
}
|
||||
|
||||
static public function fetch_by_target($target_id,$ltype = 0) {
|
||||
if (!self::isEnabled()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$x = q("select * from listeners where target_id = '%s' and ltype = %d",
|
||||
dbesc($target_id),
|
||||
intval($ltype)
|
||||
|
||||
@@ -69,12 +69,12 @@ class ThreadStream {
|
||||
case 'cards':
|
||||
$this->profile_owner = \App::$profile['profile_uid'];
|
||||
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
|
||||
$this->reload = $_SESSION['return_url'];
|
||||
//$this->reload = $_SESSION['return_url'];
|
||||
break;
|
||||
case 'articles':
|
||||
$this->profile_owner = \App::$profile['profile_uid'];
|
||||
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
|
||||
$this->reload = $_SESSION['return_url'];
|
||||
//$this->reload = $_SESSION['return_url'];
|
||||
break;
|
||||
case 'display':
|
||||
// in this mode we set profile_owner after initialisation (from conversation()) and then
|
||||
@@ -171,7 +171,7 @@ class ThreadStream {
|
||||
*/
|
||||
|
||||
|
||||
if(($item->get_data_value('id') != $item->get_data_value('parent')) && (activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE))) {
|
||||
if($item->get_data_value('id') != $item->get_data_value('parent') && activity_match($item->get_data_value('verb'), ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ class ThreadStream {
|
||||
* _ The data requested on success
|
||||
* _ false on failure
|
||||
*/
|
||||
public function get_template_data($conv_responses) {
|
||||
public function get_template_data($conv_responses, $mid_uuid_map) {
|
||||
$result = array();
|
||||
|
||||
foreach($this->threads as $item) {
|
||||
@@ -220,7 +220,7 @@ class ThreadStream {
|
||||
$item_data = $this->prepared_item;
|
||||
}
|
||||
else {
|
||||
$item_data = $item->get_template_data($conv_responses);
|
||||
$item_data = $item->get_template_data($conv_responses, $mid_uuid_map);
|
||||
}
|
||||
if(!$item_data) {
|
||||
logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR);
|
||||
|
||||
95
Zotlabs/Lib/Traits/HelpHelperTrait.php
Normal file
95
Zotlabs/Lib/Traits/HelpHelperTrait.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib\Traits;
|
||||
|
||||
use CommerceGuys\Intl\Language\LanguageRepository;
|
||||
|
||||
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'];
|
||||
|
||||
private string $file_name = '';
|
||||
private string $file_type = '';
|
||||
|
||||
/**
|
||||
* Associative array containing the detected language.
|
||||
*/
|
||||
private array $lang = [
|
||||
'language' => 'en', //! Detected language, 2-letter ISO 639-1 code ("en")
|
||||
'from_url' => false, //! true if language from URL overrides browser default
|
||||
'missing' => false, //! true if topic not found in detected language
|
||||
];
|
||||
|
||||
/**
|
||||
* Determines help language.
|
||||
*
|
||||
* If the language was specified in the URL, override the language preference
|
||||
* of the browser. Default to English if both of these are absent.
|
||||
*
|
||||
* Updates the `$lang` property of the module.
|
||||
*/
|
||||
private function determine_help_language() {
|
||||
|
||||
$language_repository = new LanguageRepository;
|
||||
$languages = $language_repository->getList();
|
||||
|
||||
if(array_key_exists(argv(1), $languages)) {
|
||||
$this->lang['language'] = argv(1);
|
||||
$this->lang['from_url'] = true;
|
||||
} else {
|
||||
if(isset(\App::$language)) {
|
||||
$this->lang['language'] = \App::$language;
|
||||
}
|
||||
|
||||
$this->lang['from_url'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the full path name of the file, given it's base path and
|
||||
* the language of the request.
|
||||
*
|
||||
* @param string $base_path The path of the file to find, relative to the
|
||||
* doc root path, and without the extension.
|
||||
*/
|
||||
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'];
|
||||
|
||||
$base_path_with_lang = "doc/{$lang}/${base_path}";
|
||||
|
||||
foreach ($valid_file_ext as $ext) {
|
||||
$path = "{$base_path_with_lang}.{$ext}";
|
||||
if (file_exists($path)) {
|
||||
$this->file_name = $path;
|
||||
$this->file_type = $ext;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->file_name) && $lang !== 'en') {
|
||||
$this->lang['missing'] = true;
|
||||
$this->find_help_file($base_path, 'en');
|
||||
}
|
||||
}
|
||||
|
||||
public function missing_translation(): bool {
|
||||
return !!$this->lang['missing'];
|
||||
}
|
||||
|
||||
public function missing_translation_message(): string {
|
||||
$prefered_language_name = get_language_name(
|
||||
$this->lang['language'],
|
||||
$this->lang['language']
|
||||
);
|
||||
|
||||
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.")
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user