mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-23 09:45:45 -04:00
Compare commits
1831 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
886be8c452 | ||
|
|
612448e4ae | ||
|
|
82db19d54c | ||
|
|
06aa3e6b8c | ||
|
|
abf985c69e | ||
|
|
c176b54f6b | ||
|
|
b24e691e7e | ||
|
|
c2e43dc1b0 | ||
|
|
7b7739c32c | ||
|
|
269172406f | ||
|
|
d95573741d | ||
|
|
faf4bcdd62 | ||
|
|
f699442bec | ||
|
|
8720931a53 | ||
|
|
d60c53cd12 | ||
|
|
6b0fe6e0a0 | ||
|
|
28f1f4cbdc | ||
|
|
508b3ce730 | ||
|
|
87ecc61fb4 | ||
|
|
0f6166da00 | ||
|
|
07e5b8295e | ||
|
|
9afdf86961 | ||
|
|
f4f1974be0 | ||
|
|
6f6399ca0f | ||
|
|
5018c0fbb8 | ||
|
|
188975ccbd | ||
|
|
5e1addc75e | ||
|
|
138beeac41 | ||
|
|
187364d94a | ||
|
|
6e74e76fcd | ||
|
|
615424d272 | ||
|
|
d40a7a609e | ||
|
|
0ec40f00a9 | ||
|
|
de054026f2 | ||
|
|
175b45d1ed | ||
|
|
e236b77817 | ||
|
|
21cd4a1b48 | ||
|
|
e9a50371f5 | ||
|
|
71f8a08e5f | ||
|
|
4419c93d80 | ||
|
|
fcc13ce02c | ||
|
|
941db04260 | ||
|
|
87d7a3053a | ||
|
|
ae11b2c281 | ||
|
|
f43577ec27 | ||
|
|
c648c38fb0 | ||
|
|
34d54fd309 | ||
|
|
891b1428cc | ||
|
|
453dd38e51 | ||
|
|
f59aefd3d9 | ||
|
|
451468d129 | ||
|
|
c0adf31da9 | ||
|
|
bb43c57b07 | ||
|
|
6c94bbc93f | ||
|
|
50422c608f | ||
|
|
7639157a49 | ||
|
|
f74cfaec5f | ||
|
|
d559b4a201 | ||
|
|
2d4064aca4 | ||
|
|
337d8ea78c | ||
|
|
4c0a26dbf9 | ||
|
|
885edd6261 | ||
|
|
011de75706 | ||
|
|
852e456d44 | ||
|
|
18136788e4 | ||
|
|
f1101808b7 | ||
|
|
791d5098a0 | ||
|
|
f2fd12fbe5 | ||
|
|
b5ab77908e | ||
|
|
25620081a1 | ||
|
|
5750e6cada | ||
|
|
394aa76a8f | ||
|
|
35c4deb884 | ||
|
|
0daccead12 | ||
|
|
e7c83a81c7 | ||
|
|
dcf8830752 | ||
|
|
3d519f478a | ||
|
|
3f0fc40ef8 | ||
|
|
820494c7a6 | ||
|
|
60b82d3690 | ||
|
|
57d9b1b332 | ||
|
|
67f8b78a7d | ||
|
|
aada997601 | ||
|
|
e5dd108bd7 | ||
|
|
ad91ab68ce | ||
|
|
66c3c32154 | ||
|
|
c9ce562369 | ||
|
|
a1f01529a7 | ||
|
|
38985dc4e2 | ||
|
|
e74c52094f | ||
|
|
e05f1f95cf | ||
|
|
b63c5f2785 | ||
|
|
685c569eaf | ||
|
|
b6e3469519 | ||
|
|
16071f300e | ||
|
|
a8de999b7c | ||
|
|
0dcbcf93c2 | ||
|
|
06273e980e | ||
|
|
c879e5de44 | ||
|
|
890290fff0 | ||
|
|
cddae14352 | ||
|
|
b3e6a3c1e2 | ||
|
|
255b6a14a8 | ||
|
|
bafbf04164 | ||
|
|
fdefa101d8 | ||
|
|
7e40eeb52a | ||
|
|
e98804693d | ||
|
|
953c294778 | ||
|
|
20d2811cd5 | ||
|
|
207df132e6 | ||
|
|
40e0fe1d25 | ||
|
|
fe3f42ce10 | ||
|
|
b4ca5c133c | ||
|
|
8f1a579597 | ||
|
|
aa69b43e0e | ||
|
|
cadd6fdfff | ||
|
|
85b97014c9 | ||
|
|
50ca95735d | ||
|
|
b55c7f794b | ||
|
|
205279f7f8 | ||
|
|
934721a98d | ||
|
|
d02a8d733e | ||
|
|
d59b81f11d | ||
|
|
b11d2c376b | ||
|
|
6d83b5b68d | ||
|
|
0ad7c8f69e | ||
|
|
e24c769f8e | ||
|
|
7cf9b85a97 | ||
|
|
dd3d65cb1c | ||
|
|
5e19632f2d | ||
|
|
cc543d1ad2 | ||
|
|
35299ed7c3 | ||
|
|
7008cf3269 | ||
|
|
6979ea44f4 | ||
|
|
81775eebe2 | ||
|
|
e70802c6ad | ||
|
|
7112bcd134 | ||
|
|
d3d5ddfb43 | ||
|
|
5580fc1954 | ||
|
|
d0e85f05af | ||
|
|
c136741db6 | ||
|
|
5724be1f8e | ||
|
|
29e89d1152 | ||
|
|
95dfde99c6 | ||
|
|
59fd3861a7 | ||
|
|
69d627a58b | ||
|
|
2772c33563 | ||
|
|
78f655f877 | ||
|
|
75a73be60c | ||
|
|
690874fc6e | ||
|
|
96de38a1f0 | ||
|
|
cef0c2ebb2 | ||
|
|
5e0f5460f2 | ||
|
|
ff8c9cfd14 | ||
|
|
b5b033fe22 | ||
|
|
5dc2f43d1d | ||
|
|
f0acb9f01e | ||
|
|
b6ca9b6020 | ||
|
|
9c6446edbe | ||
|
|
d84f0030be | ||
|
|
61f554e0d7 | ||
|
|
3b252d98b8 | ||
|
|
f5315ed6a2 | ||
|
|
c1f36802a1 | ||
|
|
ba0f24bf70 | ||
|
|
522b92128f | ||
|
|
ea77043aaf | ||
|
|
91dd877c2d | ||
|
|
e2e160b8e8 | ||
|
|
89c74868aa | ||
|
|
45a5a04189 | ||
|
|
1f41b1837f | ||
|
|
c01e1b6c33 | ||
|
|
08e7c7b249 | ||
|
|
b103993ad1 | ||
|
|
e12f375624 | ||
|
|
8cd67a5d4a | ||
|
|
31e030af69 | ||
|
|
375986437a | ||
|
|
5f93157d5a | ||
|
|
8d3c201830 | ||
|
|
612ef90523 | ||
|
|
e64856e957 | ||
|
|
8595835aa0 | ||
|
|
4d2507263d | ||
|
|
4a671fe634 | ||
|
|
ed845d93bc | ||
|
|
595f3d99b4 | ||
|
|
1e2d5b0c77 | ||
|
|
1215618589 | ||
|
|
67533ee478 | ||
|
|
3acd5dcc07 | ||
|
|
c387902a44 | ||
|
|
ad51be7dd9 | ||
|
|
3514f805ea | ||
|
|
2690159f09 | ||
|
|
902151918c | ||
|
|
5dd1ea21af | ||
|
|
b37c8bf928 | ||
|
|
923ae14c47 | ||
|
|
7ec6550734 | ||
|
|
e622802c24 | ||
|
|
244c8edfca | ||
|
|
245c0c22cd | ||
|
|
93b90ab23a | ||
|
|
765f9ffcf0 | ||
|
|
bdfdd515d8 | ||
|
|
72c6d3e7ba | ||
|
|
869ce64f87 | ||
|
|
86117c8859 | ||
|
|
96c4c72ee3 | ||
|
|
4b0d32eb14 | ||
|
|
1d705b9805 | ||
|
|
8605aee533 | ||
|
|
e4de9ef903 | ||
|
|
e529635952 | ||
|
|
21b71401d3 | ||
|
|
80bdcbb3e6 | ||
|
|
b878b69028 | ||
|
|
48440e368c | ||
|
|
a7bf07b864 | ||
|
|
a80e59812b | ||
|
|
3f784a974a | ||
|
|
5ce3565109 | ||
|
|
b25054e891 | ||
|
|
2c316c788e | ||
|
|
2fe2cc5e65 | ||
|
|
5d6a7922c1 | ||
|
|
d23e830955 | ||
|
|
762de94900 | ||
|
|
d938c79385 | ||
|
|
987a369fec | ||
|
|
586e2ef2df | ||
|
|
5edec37d57 | ||
|
|
42ef6208c1 | ||
|
|
6f508b81d6 | ||
|
|
81e2f73c98 | ||
|
|
be43d3e0fd | ||
|
|
60fd27eca4 | ||
|
|
ca4a3c3cc0 | ||
|
|
dfad87f674 | ||
|
|
743e575701 | ||
|
|
be627c3f3a | ||
|
|
80fdf53cc3 | ||
|
|
759f297aae | ||
|
|
1a41c44c2f | ||
|
|
88b014e9a7 | ||
|
|
bd0b8d768e | ||
|
|
f422362747 | ||
|
|
34217f5f90 | ||
|
|
56e503149d | ||
|
|
04af502e3a | ||
|
|
f2c1fd2a48 | ||
|
|
a86fd554a3 | ||
|
|
ef0a8bcde0 | ||
|
|
c38fc0b906 | ||
|
|
2758d3c3eb | ||
|
|
521a5074c9 | ||
|
|
430c48e828 | ||
|
|
2e747bec6f | ||
|
|
d945789e1b | ||
|
|
de306cd7b8 | ||
|
|
aedde6600e | ||
|
|
9c8d732081 | ||
|
|
5d1e10522f | ||
|
|
ba0410dd24 | ||
|
|
da44cef9a3 | ||
|
|
e9227b0ffe | ||
|
|
9299aff2af | ||
|
|
a9377d6a3f | ||
|
|
b223b71d0d | ||
|
|
02cf85fa34 | ||
|
|
76a6e0b6fc | ||
|
|
2a2f032f17 | ||
|
|
e7ddd1a481 | ||
|
|
813ab2c5ed | ||
|
|
4acdf9e817 | ||
|
|
465da3a942 | ||
|
|
fb601cc280 | ||
|
|
25b9776bf6 | ||
|
|
5271232aa5 | ||
|
|
7fa70108c4 | ||
|
|
ff09b2131e | ||
|
|
df758f40ef | ||
|
|
1d8dd949dc | ||
|
|
9dd333a2f4 | ||
|
|
d53b3b242d | ||
|
|
8e0e4b7b92 | ||
|
|
adee24af6f | ||
|
|
1b161b0ee4 | ||
|
|
5aaa8f44a2 | ||
|
|
1fbc6fa431 | ||
|
|
6177ec9134 | ||
|
|
bd4867ef39 | ||
|
|
0189d06375 | ||
|
|
aafdeb9000 | ||
|
|
e9a264cb43 | ||
|
|
b996d82c5f | ||
|
|
c53794a8a2 | ||
|
|
170b2e4465 | ||
|
|
4e0fc81e5d | ||
|
|
3b865d432f | ||
|
|
646dce7765 | ||
|
|
88a68f96da | ||
|
|
32bdf42913 | ||
|
|
53a010d1d4 | ||
|
|
a9e19cb89e | ||
|
|
4878611987 | ||
|
|
2c777acb25 | ||
|
|
49df57df45 | ||
|
|
374c30999a | ||
|
|
2ab480188a | ||
|
|
c4c47f7777 | ||
|
|
c36b2ca915 | ||
|
|
e55a1a6aa8 | ||
|
|
21e5b05b14 | ||
|
|
ea845aeacd | ||
|
|
ee3b077f26 | ||
|
|
393cee6619 | ||
|
|
d9196bb82a | ||
|
|
5ecbbfc7df | ||
|
|
9244ee8094 | ||
|
|
0b7ca61958 | ||
|
|
c56b140387 | ||
|
|
3e7d3a20af | ||
|
|
2d2cab0aba | ||
|
|
364346b07c | ||
|
|
be15a395d8 | ||
|
|
845f7e9382 | ||
|
|
976d6baf6a | ||
|
|
f9271bb0bd | ||
|
|
06f03eb13a | ||
|
|
1a1c0ca72c | ||
|
|
73f2db09ae | ||
|
|
be533679dd | ||
|
|
e31903cbc9 | ||
|
|
33d417955d | ||
|
|
9f0f794a0a | ||
|
|
33e4d7c0d8 | ||
|
|
ad30834123 | ||
|
|
fba64e9451 | ||
|
|
9b5e270379 | ||
|
|
ea5131db88 | ||
|
|
7ae86d29d2 | ||
|
|
13ff9a897d | ||
|
|
4db38ec64a | ||
|
|
29c5a65e8f | ||
|
|
dd2ffae8bf | ||
|
|
ca969cd0ed | ||
|
|
4f95b44ff2 | ||
|
|
cb7aec0da5 | ||
|
|
62eebc86f6 | ||
|
|
5ea7196e78 | ||
|
|
fcc47e69e4 | ||
|
|
d2f1c37431 | ||
|
|
817fe8d485 | ||
|
|
1dbd85322d | ||
|
|
fe90096ace | ||
|
|
ad60309187 | ||
|
|
634a515ec1 | ||
|
|
01abb82c37 | ||
|
|
1c88a8d4a0 | ||
|
|
ce77f82966 | ||
|
|
573af9e366 | ||
|
|
774cc852d4 | ||
|
|
c0735a5ca2 | ||
|
|
fa752b0ac1 | ||
|
|
3f69fc70f1 | ||
|
|
137f56f994 | ||
|
|
e2cbcf7039 | ||
|
|
64f8df0a0d | ||
|
|
274d556ec1 | ||
|
|
f28c3b441e | ||
|
|
4eaa893e0b | ||
|
|
36e969fd79 | ||
|
|
d8f16960c8 | ||
|
|
101a7648ee | ||
|
|
70a104f24f | ||
|
|
0f27db6271 | ||
|
|
56ec55110a | ||
|
|
570497071d | ||
|
|
49dee6312f | ||
|
|
63a6b4a162 | ||
|
|
ec4dea0920 | ||
|
|
7270da6a28 | ||
|
|
8cd66145bd | ||
|
|
92ee27349c | ||
|
|
a88233a045 | ||
|
|
0259130cf3 | ||
|
|
d0a1f0b8f9 | ||
|
|
97dd350c61 | ||
|
|
dc3b09c8f3 | ||
|
|
c8c4513af9 | ||
|
|
3201a4bec5 | ||
|
|
9da8e30c37 | ||
|
|
6bfac1a907 | ||
|
|
d0c7c99d5e | ||
|
|
934bcf5336 | ||
|
|
5b88873530 | ||
|
|
b161b02c51 | ||
|
|
ddc544e00a | ||
|
|
97d5ffe056 | ||
|
|
13319985fd | ||
|
|
e3aaa39f9e | ||
|
|
b6efb02ed2 | ||
|
|
c358d8326e | ||
|
|
f40fedcad6 | ||
|
|
b4973ede44 | ||
|
|
81338e8086 | ||
|
|
4270e17bc4 | ||
|
|
1329662edc | ||
|
|
249427365b | ||
|
|
326644104c | ||
|
|
1520a26e0f | ||
|
|
6ffdc1b642 | ||
|
|
22d8523e76 | ||
|
|
2d3740b912 | ||
|
|
c8ab5db768 | ||
|
|
c656478230 | ||
|
|
3d02758fee | ||
|
|
f473b5abfb | ||
|
|
22d68ddf08 | ||
|
|
2cba88f1eb | ||
|
|
f132436af3 | ||
|
|
fae70bf0a7 | ||
|
|
ffd2faf8a0 | ||
|
|
64a8913385 | ||
|
|
266dcd44bb | ||
|
|
8851921d6d | ||
|
|
c76ff4249e | ||
|
|
dbfe748d27 | ||
|
|
4ee809bed6 | ||
|
|
4ebf6cda5d | ||
|
|
a04b6d178b | ||
|
|
c8b45c3449 | ||
|
|
1bb74a5a01 | ||
|
|
ef94072cee | ||
|
|
ff3ff2478d | ||
|
|
2757822cd8 | ||
|
|
2cb0cade7b | ||
|
|
191e01e3ec | ||
|
|
8c65e9cb4a | ||
|
|
79968ea07a | ||
|
|
7a0d9a4494 | ||
|
|
06d1cf83d2 | ||
|
|
de058901c2 | ||
|
|
a40b882d72 | ||
|
|
46242aeaae | ||
|
|
ad040a0b11 | ||
|
|
4eaba326ce | ||
|
|
fd48f9d173 | ||
|
|
104c45f6e6 | ||
|
|
f4a71db42d | ||
|
|
1ac2b93fd8 | ||
|
|
03c1419ad0 | ||
|
|
18938280f5 | ||
|
|
01334d761a | ||
|
|
446204f7d8 | ||
|
|
328900cf3b | ||
|
|
837dbb7a14 | ||
|
|
c9794439bc | ||
|
|
079c13e633 | ||
|
|
7b8c85cf3f | ||
|
|
c229f058b4 | ||
|
|
e2b10f52e0 | ||
|
|
2b8afd5580 | ||
|
|
7e89d816d7 | ||
|
|
77c87bcccf | ||
|
|
b7a655917e | ||
|
|
d8bfa5dd96 | ||
|
|
88eb19165b | ||
|
|
2828b8cf5c | ||
|
|
b1b9dbe55f | ||
|
|
579adb4897 | ||
|
|
a9d52cd296 | ||
|
|
c71422e909 | ||
|
|
03506bd6cf | ||
|
|
244936b0fd | ||
|
|
f430a24fa3 | ||
|
|
ecb1c78173 | ||
|
|
42631b5943 | ||
|
|
109f9eed61 | ||
|
|
c7fdc53795 | ||
|
|
602ca91700 | ||
|
|
4cfc0b1a64 | ||
|
|
3d5fdd086b | ||
|
|
223c4c7b9a | ||
|
|
f7e925beaa | ||
|
|
e588ea8a8b | ||
|
|
91cad21d33 | ||
|
|
d6b9c8b93d | ||
|
|
a7273668d8 | ||
|
|
b1f74f4ef4 | ||
|
|
c640d1c599 | ||
|
|
9d0f71bfcb | ||
|
|
bbca6be0f9 | ||
|
|
31e1e9cbfb | ||
|
|
6de823b532 | ||
|
|
69878ed628 | ||
|
|
27ae9c9d34 | ||
|
|
52e698cae6 | ||
|
|
6a0ac591d1 | ||
|
|
328685d2fb | ||
|
|
806c738923 | ||
|
|
9c2d48bcd4 | ||
|
|
d8802e4fc8 | ||
|
|
2c8a243ece | ||
|
|
3372fb0761 | ||
|
|
af7a31cd14 | ||
|
|
cb2996a40c | ||
|
|
ea237a97a1 | ||
|
|
530b1d038f | ||
|
|
a31981966e | ||
|
|
84183d9f7e | ||
|
|
805f8bf983 | ||
|
|
67c9b5d049 | ||
|
|
44b935f875 | ||
|
|
cade25a112 | ||
|
|
a4831b0f7c | ||
|
|
ec9418b262 | ||
|
|
cec2e92fe3 | ||
|
|
625438ff64 | ||
|
|
6cfaa5cba3 | ||
|
|
31fea1014e | ||
|
|
898fea1e0e | ||
|
|
4b3979df04 | ||
|
|
ac52bebb88 | ||
|
|
c568f7b8d1 | ||
|
|
d925ec6759 | ||
|
|
c136c142b8 | ||
|
|
38be2386dd | ||
|
|
643b2f9205 | ||
|
|
ffe429be65 | ||
|
|
4a56b77f64 | ||
|
|
9773ab7aab | ||
|
|
6c02fa40f1 | ||
|
|
632996f53e | ||
|
|
710448e73f | ||
|
|
084177a20c | ||
|
|
5a2c62466e | ||
|
|
b739f91caa | ||
|
|
b1590ad645 | ||
|
|
f49010bb12 | ||
|
|
6e1c3b6d48 | ||
|
|
bcdd75b817 | ||
|
|
0271f2a1ae | ||
|
|
0c1c386a0a | ||
|
|
a3acec9674 | ||
|
|
4eaddd1279 | ||
|
|
eb3dbcce7b | ||
|
|
3ecf1cab5e | ||
|
|
c536526196 | ||
|
|
b2de12442d | ||
|
|
8f5cb0c45a | ||
|
|
3b4503c971 | ||
|
|
c358aa2806 | ||
|
|
938d26ba3e | ||
|
|
b23751128b | ||
|
|
d54ff4fae5 | ||
|
|
720d3dcedc | ||
|
|
ce4fc30439 | ||
|
|
b39474456f | ||
|
|
25cd9b4983 | ||
|
|
2d65ce542c | ||
|
|
c2b691fd01 | ||
|
|
ae691bdc7c | ||
|
|
ba566fd64b | ||
|
|
85c07d57fe | ||
|
|
16fd618380 | ||
|
|
06f2979e04 | ||
|
|
1ff9d1afdd | ||
|
|
a776f69a59 | ||
|
|
a574290235 | ||
|
|
84c9ae04fc | ||
|
|
c74c41c3b8 | ||
|
|
7cf73e0533 | ||
|
|
03e9ed71b4 | ||
|
|
e7e79f7423 | ||
|
|
589af1f9ee | ||
|
|
e7f25b8466 | ||
|
|
2100441b54 | ||
|
|
082826ee44 | ||
|
|
93ad3eb6f1 | ||
|
|
177209b5e9 | ||
|
|
47d80df81c | ||
|
|
3d6fa049da | ||
|
|
16738dfe7f | ||
|
|
c28ba4be37 | ||
|
|
8bcdc24fcb | ||
|
|
b36eb9a91c | ||
|
|
989fbe70cd | ||
|
|
85cf25a2a8 | ||
|
|
7bb94f9993 | ||
|
|
1297c8d2ae | ||
|
|
ed28ef185e | ||
|
|
9d97cc2a1d | ||
|
|
23acf02d58 | ||
|
|
60311eb04b | ||
|
|
b9a8b9e47b | ||
|
|
b7bac45427 | ||
|
|
7d05b8e5fd | ||
|
|
d5ae9aedc4 | ||
|
|
1b216e6019 | ||
|
|
83256c9ccd | ||
|
|
9f029336ca | ||
|
|
95476cf33c | ||
|
|
bf7c96807a | ||
|
|
d4a6aa7801 | ||
|
|
b767bda410 | ||
|
|
a39d436f9f | ||
|
|
50dbe1e62d | ||
|
|
be81a40b2b | ||
|
|
bbcb237f5b | ||
|
|
33be244d8a | ||
|
|
ca75619518 | ||
|
|
82acfb75a1 | ||
|
|
fc9e6d289a | ||
|
|
6838342d62 | ||
|
|
69b25e490e | ||
|
|
b8d7647c48 | ||
|
|
989443a569 | ||
|
|
c50a311ff3 | ||
|
|
b37e5a426a | ||
|
|
5e76318e44 | ||
|
|
8ed3971ef0 | ||
|
|
c2b6f0bc28 | ||
|
|
2c42daf609 | ||
|
|
8e2446a2fc | ||
|
|
19bb9e0181 | ||
|
|
e9b2dacb61 | ||
|
|
3df5d854b8 | ||
|
|
9545a81166 | ||
|
|
1712eceaf9 | ||
|
|
7d8c6cb9ed | ||
|
|
f123809d29 | ||
|
|
7abcdd34af | ||
|
|
ead56c59e2 | ||
|
|
19a8dfaa5c | ||
|
|
fa45ea1d84 | ||
|
|
8789edb65d | ||
|
|
b6abc034cf | ||
|
|
c92ea70453 | ||
|
|
07eee20525 | ||
|
|
6c9130be46 | ||
|
|
51f00cda92 | ||
|
|
7973567a7c | ||
|
|
b81b18814e | ||
|
|
bbfe71b0c6 | ||
|
|
7404183830 | ||
|
|
43aea3ce38 | ||
|
|
cbaf4b7536 | ||
|
|
570d84c031 | ||
|
|
9eeccc087d | ||
|
|
7404a8ec1a | ||
|
|
bfae86bdb6 | ||
|
|
66f6a1d186 | ||
|
|
17a4aa983e | ||
|
|
2a0a06d74a | ||
|
|
ccaa93655a | ||
|
|
65bc363685 | ||
|
|
293d411efb | ||
|
|
2a287e6def | ||
|
|
d96f4340e8 | ||
|
|
d3cbbe029c | ||
|
|
a1ccacb825 | ||
|
|
b04915161b | ||
|
|
8cb968c4b0 | ||
|
|
f645c6f3a5 | ||
|
|
4c1c690816 | ||
|
|
537a7cf03d | ||
|
|
662e8f8a4c | ||
|
|
7397348b9c | ||
|
|
5c43013692 | ||
|
|
908875a052 | ||
|
|
41ce2da080 | ||
|
|
6add6ce79b | ||
|
|
0fe9c029ab | ||
|
|
a6522b34c7 | ||
|
|
229f99fe6b | ||
|
|
bdc269d445 | ||
|
|
ff63132a32 | ||
|
|
e7fb22edc1 | ||
|
|
3c59303b68 | ||
|
|
fb4504c5a3 | ||
|
|
db22578c16 | ||
|
|
300727b8cf | ||
|
|
448fb14fc4 | ||
|
|
c42e8613e5 | ||
|
|
12de30a2b1 | ||
|
|
6f93d9848c | ||
|
|
3d019fa2dd | ||
|
|
d5aeb13601 | ||
|
|
230f7ab6d4 | ||
|
|
d71dd21abc | ||
|
|
0d00b72569 | ||
|
|
00f6deb9bd | ||
|
|
cce5054aec | ||
|
|
544ef3bc58 | ||
|
|
124cc43962 | ||
|
|
4237dd457e | ||
|
|
88ebbd90d8 | ||
|
|
298acb9645 | ||
|
|
c4f4edd743 | ||
|
|
258a4e5627 | ||
|
|
e1400e5745 | ||
|
|
593688d539 | ||
|
|
aed6823051 | ||
|
|
96f9e51546 | ||
|
|
161ea6d51f | ||
|
|
88e755037b | ||
|
|
cde706748a | ||
|
|
3e833a5bcd | ||
|
|
475a39ff90 | ||
|
|
2dd2b755f1 | ||
|
|
a6516341c5 | ||
|
|
9a70c3c275 | ||
|
|
5998445841 | ||
|
|
d9c39d0c41 | ||
|
|
4038b78377 | ||
|
|
dce8516da4 | ||
|
|
bde429cff6 | ||
|
|
4c8d33d1eb | ||
|
|
fac7826efa | ||
|
|
d439dee736 | ||
|
|
295c08fcf3 | ||
|
|
efa11cbc74 | ||
|
|
4a8e222763 | ||
|
|
75b9c7d6b8 | ||
|
|
d1648fb258 | ||
|
|
34cda095fe | ||
|
|
dad7bc82c3 | ||
|
|
0ee65ee954 | ||
|
|
ae0780fe3f | ||
|
|
d2a65ab1be | ||
|
|
f4516826ef | ||
|
|
b894380f86 | ||
|
|
b48a9d3f75 | ||
|
|
21b398252a | ||
|
|
80e03268fd | ||
|
|
135b3cf1ef | ||
|
|
b9e083da61 | ||
|
|
74aa446190 | ||
|
|
0d7548a381 | ||
|
|
428b2cca21 | ||
|
|
28a316f73f | ||
|
|
0532d639c2 | ||
|
|
c17717c5db | ||
|
|
8b00913579 | ||
|
|
cf95c4878d | ||
|
|
4958e3b42c | ||
|
|
cc3edeb6f5 | ||
|
|
20c296ce53 | ||
|
|
5ccbcb44f7 | ||
|
|
adcf28af7c | ||
|
|
5b206cd4a7 | ||
|
|
1eb70b66d8 | ||
|
|
3c1ff1fc63 | ||
|
|
d711f2ad4c | ||
|
|
ae8a1c992a | ||
|
|
580d3db5a8 | ||
|
|
042cc96968 | ||
|
|
d177043c9f | ||
|
|
4c1e2c2dd8 | ||
|
|
7dcb0cc11b | ||
|
|
837d9a4df0 | ||
|
|
ec1d5ead93 | ||
|
|
f485ed174d | ||
|
|
e8560d56f5 | ||
|
|
3a937fb969 | ||
|
|
c1aa96ebf7 | ||
|
|
17e012afc6 | ||
|
|
1c6796f907 | ||
|
|
3e133bbfa3 | ||
|
|
6c8d1bdffe | ||
|
|
59fc495593 | ||
|
|
60827bdcc4 | ||
|
|
f2c73c0f45 | ||
|
|
78492d0037 | ||
|
|
2b08519f5a | ||
|
|
c86b35da70 | ||
|
|
b2003e2c3c | ||
|
|
8a08cceccb | ||
|
|
9284b60a79 | ||
|
|
b69f8a3f29 | ||
|
|
8ea7c08f43 | ||
|
|
78197aa625 | ||
|
|
f992feb71c | ||
|
|
fcb065bcb2 | ||
|
|
cf66e66db8 | ||
|
|
63aa3948e5 | ||
|
|
3940fa5659 | ||
|
|
7899ed6f69 | ||
|
|
5e44239657 | ||
|
|
697fbf33c5 | ||
|
|
901785663e | ||
|
|
9e4ff8ce25 | ||
|
|
5f1b2b4bf7 | ||
|
|
271d280c91 | ||
|
|
8f708fef9c | ||
|
|
38de059156 | ||
|
|
f0b40ac15e | ||
|
|
5c47c9ed95 | ||
|
|
dafac11aaa | ||
|
|
1fc81457a1 | ||
|
|
0d47bb6878 | ||
|
|
17cd452fff | ||
|
|
f6f7e7e8d2 | ||
|
|
004861fbb7 | ||
|
|
483d450af4 | ||
|
|
decc14c324 | ||
|
|
1134be8d30 | ||
|
|
fb65c54123 | ||
|
|
fe803135d8 | ||
|
|
908ebed9fd | ||
|
|
bdb6b0d237 | ||
|
|
73a0866ac4 | ||
|
|
e6b1b20565 | ||
|
|
e40ea62c7c | ||
|
|
7864579b1e | ||
|
|
b62eb665c5 | ||
|
|
c72716eca7 | ||
|
|
530d816df6 | ||
|
|
23c47f78ea | ||
|
|
8727f12b18 | ||
|
|
4a4c43bb2c | ||
|
|
0159b631fc | ||
|
|
e74361c4db | ||
|
|
21299c6fc1 | ||
|
|
eec42d3bb3 | ||
|
|
bd049eddd4 | ||
|
|
e762347080 | ||
|
|
53ad04cdc4 | ||
|
|
148c3f9dc5 | ||
|
|
6f1188f44f | ||
|
|
78868314a7 | ||
|
|
dc2f293089 | ||
|
|
c7a0526428 | ||
|
|
498c021aec | ||
|
|
5ee133843f | ||
|
|
9ad2902add | ||
|
|
ef75d27afb | ||
|
|
965c51c2d4 | ||
|
|
05604e4bd2 | ||
|
|
fd7d497cd1 | ||
|
|
a974d0d52d | ||
|
|
5a6b14f878 | ||
|
|
de9a7f0fa9 | ||
|
|
3009c88d24 | ||
|
|
c850a61a89 | ||
|
|
f3fa2d853a | ||
|
|
a982aecd5b | ||
|
|
52bd27a028 | ||
|
|
e5e16da8cb | ||
|
|
3a2fdec241 | ||
|
|
b0adb70ffc | ||
|
|
2f4c619d51 | ||
|
|
6e36820b1b | ||
|
|
209d06a8f7 | ||
|
|
4a6d050e22 | ||
|
|
b033597ada | ||
|
|
08b804cd2d | ||
|
|
89342ca9fb | ||
|
|
892f4b4182 | ||
|
|
de7891771d | ||
|
|
602768209b | ||
|
|
73b1f8fcdd | ||
|
|
e1b923ab7d | ||
|
|
bed9876d68 | ||
|
|
d184e2708f | ||
|
|
580c3f4ffe | ||
|
|
158b8aea38 | ||
|
|
d22766f458 | ||
|
|
70391243dc | ||
|
|
61eef68ff3 | ||
|
|
41cc2854c5 | ||
|
|
ec68ede79f | ||
|
|
478014f02a | ||
|
|
aff7c2d771 | ||
|
|
00dd52317a | ||
|
|
17522b31e9 | ||
|
|
163b1ee9f8 | ||
|
|
7b9a992f83 | ||
|
|
4efb258671 | ||
|
|
7532358806 | ||
|
|
13c05e7937 | ||
|
|
c6e9bca76c | ||
|
|
3706afbd01 | ||
|
|
bcd0802ea4 | ||
|
|
9360148829 | ||
|
|
a6165c00ce | ||
|
|
a5826fec25 | ||
|
|
839c6668cf | ||
|
|
e9a9fc5050 | ||
|
|
426668cd2e | ||
|
|
926d7c56a6 | ||
|
|
9934dbfe69 | ||
|
|
b6314c109d | ||
|
|
f8955f90b8 | ||
|
|
9248fc96b3 | ||
|
|
2875ee2423 | ||
|
|
36f707b25e | ||
|
|
2a05bd9ed6 | ||
|
|
b7db9944ec | ||
|
|
86f7d08483 | ||
|
|
1358a81c32 | ||
|
|
09ad48c12b | ||
|
|
aa137fb2d2 | ||
|
|
09284d512d | ||
|
|
02fd7e51ff | ||
|
|
b359b89aa1 | ||
|
|
873b20677e | ||
|
|
a049664219 | ||
|
|
64c6e25896 | ||
|
|
9f9122ab8e | ||
|
|
d0661cd4a3 | ||
|
|
707b19dc35 | ||
|
|
6fd15d66a7 | ||
|
|
8c9a814e18 | ||
|
|
74ef5f38e9 | ||
|
|
624a3ee1a7 | ||
|
|
fc658a25d7 | ||
|
|
308619a726 | ||
|
|
e87d8d9856 | ||
|
|
7594264725 | ||
|
|
69533ce8f5 | ||
|
|
9fac43a3a3 | ||
|
|
b00db39739 | ||
|
|
6f2a584279 | ||
|
|
de717268f7 | ||
|
|
e27b19c756 | ||
|
|
045cb461f1 | ||
|
|
088c0eedc6 | ||
|
|
e5137b03fc | ||
|
|
76d34a4d74 | ||
|
|
ae4f0e5728 | ||
|
|
5df59027ad | ||
|
|
c888e33f04 | ||
|
|
1a56ecaa39 | ||
|
|
d778c3cf19 | ||
|
|
8bf57c6226 | ||
|
|
3c762b8809 | ||
|
|
3561fd7c43 | ||
|
|
66bfc0ec64 | ||
|
|
7d0e576e3b | ||
|
|
aa330bc8c7 | ||
|
|
b4de492e0d | ||
|
|
5bf3114e6f | ||
|
|
d2b1a2e5a3 | ||
|
|
4b01f6359b | ||
|
|
bcfa62f45a | ||
|
|
e7e8a2ca5f | ||
|
|
5edeb0250b | ||
|
|
0c2657df78 | ||
|
|
e4c57e8031 | ||
|
|
6a25548097 | ||
|
|
db7cbdfc44 | ||
|
|
2f26badb84 | ||
|
|
f7e665c42f | ||
|
|
3bc44ee451 | ||
|
|
125de855ef | ||
|
|
3881ebcce0 | ||
|
|
bef5324fea | ||
|
|
c2655370e0 | ||
|
|
d017e34795 | ||
|
|
aa44da35ba | ||
|
|
5c4c6e68f6 | ||
|
|
a435363b94 | ||
|
|
d6634eb14e | ||
|
|
afee2cf71a | ||
|
|
79b0a6ba9c | ||
|
|
0c2438b36a | ||
|
|
d6da46f94b | ||
|
|
562e39c9c5 | ||
|
|
2d08e0955a | ||
|
|
baffa969d3 | ||
|
|
1fbc8739b9 | ||
|
|
b9dec84489 | ||
|
|
6feb864c38 | ||
|
|
b6db1898b1 | ||
|
|
de902d179e | ||
|
|
58b77e3427 | ||
|
|
cdcac86256 | ||
|
|
79b05e48e8 | ||
|
|
541146e8ce | ||
|
|
97b161c536 | ||
|
|
ba3a6ecb52 | ||
|
|
cf27b7440d | ||
|
|
407b9c9cd7 | ||
|
|
d0055310ba | ||
|
|
02f5fa32af | ||
|
|
b6590e95b5 | ||
|
|
ec65211d54 | ||
|
|
8dfa08f146 | ||
|
|
daef2d0546 | ||
|
|
15eaa80301 | ||
|
|
1e924a8530 | ||
|
|
23995ccb07 | ||
|
|
a4f2603454 | ||
|
|
cc860b4a76 | ||
|
|
0be82602ce | ||
|
|
b42c42692e | ||
|
|
7fcbff3ceb | ||
|
|
efec0af394 | ||
|
|
aafecd9d1e | ||
|
|
e37c43ea06 | ||
|
|
3fac7b5bb7 | ||
|
|
9b90114d03 | ||
|
|
7c5cfe6697 | ||
|
|
d1fd69337f | ||
|
|
3fc218111a | ||
|
|
c63fb0fc6b | ||
|
|
6fe4ac241d | ||
|
|
c385b80807 | ||
|
|
97f36fa46f | ||
|
|
856d4b39d1 | ||
|
|
01abd73a2a | ||
|
|
375c2a87c7 | ||
|
|
6ca507f8dd | ||
|
|
86b4a53858 | ||
|
|
8959ba9b82 | ||
|
|
a62a230d3d | ||
|
|
cc45129e9f | ||
|
|
bffc9d5aba | ||
|
|
f2b121cd58 | ||
|
|
fd30be7644 | ||
|
|
d9052c7e3c | ||
|
|
dcfe10b691 | ||
|
|
914a096b42 | ||
|
|
5fa9dcbc7e | ||
|
|
93ec01e0a1 | ||
|
|
bbc98db6b4 | ||
|
|
1f8d29a221 | ||
|
|
d267dd2515 | ||
|
|
51954c7f3d | ||
|
|
df842a8e8d | ||
|
|
60919488f1 | ||
|
|
4dbaaa63bb | ||
|
|
8cc4003837 | ||
|
|
35790c584b | ||
|
|
09d7cf2cc1 | ||
|
|
58d7c7f6ae | ||
|
|
cab24836d8 | ||
|
|
cf9ef615c9 | ||
|
|
8c96032b2b | ||
|
|
d256551907 | ||
|
|
e800e2db2b | ||
|
|
cc9f41df5f | ||
|
|
bb3784d8dd | ||
|
|
e5539c0d01 | ||
|
|
c997360b4a | ||
|
|
ea8621d6ec | ||
|
|
88fa18204f | ||
|
|
ac05a2ede7 | ||
|
|
808baf203d | ||
|
|
beeafc6bc5 | ||
|
|
6f8c977e73 | ||
|
|
9a2fbdde20 | ||
|
|
b325b2c003 | ||
|
|
feda23587c | ||
|
|
e8f3b7f853 | ||
|
|
e28341ca4b | ||
|
|
6c11a020ee | ||
|
|
7200c2ac0c | ||
|
|
732ca49b02 | ||
|
|
ee976ed460 | ||
|
|
06ac3e896a | ||
|
|
6ce0f6e806 | ||
|
|
e006586275 | ||
|
|
e9d6b17a00 | ||
|
|
bf2f199f37 | ||
|
|
718ca548be | ||
|
|
51c0dc070a | ||
|
|
d5e0d52bc4 | ||
|
|
f6b99db738 | ||
|
|
ef69294072 | ||
|
|
c56d395c90 | ||
|
|
778e9141d8 | ||
|
|
c70a4662b4 | ||
|
|
e441a31051 | ||
|
|
9f5ec5cc50 | ||
|
|
825ded2e08 | ||
|
|
a7c3776557 | ||
|
|
1e7cfc2644 | ||
|
|
c6fd32ffde | ||
|
|
5f551a8b47 | ||
|
|
f73ff57148 | ||
|
|
c538d7372e | ||
|
|
4e7804ca75 | ||
|
|
8fe715983a | ||
|
|
4a3fb07d5f | ||
|
|
f5062c0507 | ||
|
|
f0d7a17b72 | ||
|
|
b89d2d7580 | ||
|
|
7a7f57fa45 | ||
|
|
047dd31724 | ||
|
|
0ce1a200f7 | ||
|
|
0e0024218f | ||
|
|
4886d088e9 | ||
|
|
6eec6e2d65 | ||
|
|
6c12880f5b | ||
|
|
eb472111a8 | ||
|
|
8d8b7ed567 | ||
|
|
681dc70205 | ||
|
|
130cfbf231 | ||
|
|
940e4a6152 | ||
|
|
38f7d9ad37 | ||
|
|
e896d316f2 | ||
|
|
af690b64d6 | ||
|
|
699aad8626 | ||
|
|
4382e53acb | ||
|
|
832adf92a6 | ||
|
|
33e2582918 | ||
|
|
1c2f413211 | ||
|
|
2300581c93 | ||
|
|
03c4fba730 | ||
|
|
75a8b209f5 | ||
|
|
d554b41fea | ||
|
|
b0db1f827e | ||
|
|
3070baf04e | ||
|
|
72629ca511 | ||
|
|
1c39fc71d9 | ||
|
|
0bb59b66be | ||
|
|
31b177f8ad | ||
|
|
8ee5ced08d | ||
|
|
c96a1632f5 | ||
|
|
b3b2649814 | ||
|
|
95805d2e7c | ||
|
|
d4b92141fd | ||
|
|
829e915c90 | ||
|
|
aaffc7485d | ||
|
|
9ea1d6e8af | ||
|
|
17661b4b5f | ||
|
|
32874b89ca | ||
|
|
d4a038c437 | ||
|
|
59fed33797 | ||
|
|
feea137dbf | ||
|
|
70e4a2c4fa | ||
|
|
696359daba | ||
|
|
5695350e98 | ||
|
|
4e3a0720c3 | ||
|
|
dc56d8560d | ||
|
|
81ecea29c8 | ||
|
|
ad58697521 | ||
|
|
6ca7527ec9 | ||
|
|
8ced3699c2 | ||
|
|
c4de5b45df | ||
|
|
71056e1db1 | ||
|
|
f94faeeace | ||
|
|
80f56a1315 | ||
|
|
485f5a07ed | ||
|
|
821af482f0 | ||
|
|
b2d1fadf66 | ||
|
|
3b73e5223e | ||
|
|
6a964e7caf | ||
|
|
a6f06c2d94 | ||
|
|
a85f0a93c6 | ||
|
|
250387c7e5 | ||
|
|
dde7144f5a | ||
|
|
68733a2bc0 | ||
|
|
b2d3a11de8 | ||
|
|
a024e4c10a | ||
|
|
db6e4d1c32 | ||
|
|
8393c382c3 | ||
|
|
5c0e3688fe | ||
|
|
1e6c07246e | ||
|
|
e5370971d6 | ||
|
|
090d921006 | ||
|
|
39c0a7525b | ||
|
|
407b02bde8 | ||
|
|
da7912b879 | ||
|
|
02c08aed12 | ||
|
|
87668f7fa8 | ||
|
|
001734a725 | ||
|
|
276ab3eae3 | ||
|
|
1b976f30f3 | ||
|
|
019afe2a1a | ||
|
|
37ebcd3b4f | ||
|
|
5ad6eeccdf | ||
|
|
65cd33cb15 | ||
|
|
4aa59226d7 | ||
|
|
d53c98860d | ||
|
|
d022e1acce | ||
|
|
98100520eb | ||
|
|
42526fc2dc | ||
|
|
9c76afa2a3 | ||
|
|
943db4496b | ||
|
|
4a77b6673b | ||
|
|
62b31b1e4a | ||
|
|
ddde4e1965 | ||
|
|
96a99935ef | ||
|
|
60c003733e | ||
|
|
9def9a5cb7 | ||
|
|
145295302d | ||
|
|
302d2dbd51 | ||
|
|
49ba3ffee6 | ||
|
|
d83ce0863a | ||
|
|
cf844cb27c | ||
|
|
5ccef18d4e | ||
|
|
40bbdfdf6a | ||
|
|
ad8ad0ccd7 | ||
|
|
1cf012650b | ||
|
|
4f280b5497 | ||
|
|
5ee7009271 | ||
|
|
07f850ed15 | ||
|
|
1b6fbe3a2e | ||
|
|
b1b415ec5b | ||
|
|
8730bbac2f | ||
|
|
e8918ca149 | ||
|
|
82478eef09 | ||
|
|
892e9cd835 | ||
|
|
3dd6499ac4 | ||
|
|
109c66aea3 | ||
|
|
24b0f8e27e | ||
|
|
1a76e83fa4 | ||
|
|
2fa788b01b | ||
|
|
028cbdcffa | ||
|
|
8aefbd911b | ||
|
|
f37387de80 | ||
|
|
4f705fc3f8 | ||
|
|
5b727065cf | ||
|
|
952e466d91 | ||
|
|
c1cc76119c | ||
|
|
9d156141b1 | ||
|
|
8c92b0cd3a | ||
|
|
dd515da889 | ||
|
|
2862b69d56 | ||
|
|
db8e46184b | ||
|
|
99a7cd3cfb | ||
|
|
75746d714a | ||
|
|
983d6d3b42 | ||
|
|
060dd8b020 | ||
|
|
b5be0a2e3e | ||
|
|
46a687b0a6 | ||
|
|
4ff7aa4352 | ||
|
|
750d1f820d | ||
|
|
f046a34d34 | ||
|
|
0d165920bb | ||
|
|
9e3a4402e0 | ||
|
|
34d7aea1be | ||
|
|
e2abc0b727 | ||
|
|
a677a68ab7 | ||
|
|
df228237de | ||
|
|
fc2a038ee1 | ||
|
|
619b39f955 | ||
|
|
becaa3b920 | ||
|
|
c0b9ab930d | ||
|
|
f106b1db15 | ||
|
|
958217dd55 | ||
|
|
2f80fdae97 | ||
|
|
9507f191b0 | ||
|
|
92f5d8c8be | ||
|
|
8535eb7bf5 | ||
|
|
c9604eaabf | ||
|
|
3bc214e544 | ||
|
|
43cec4398d | ||
|
|
335394aaa1 | ||
|
|
c9615cc19c | ||
|
|
5315d8fe3f | ||
|
|
75dedb3345 | ||
|
|
134dfb8804 | ||
|
|
86f4a8d33a | ||
|
|
abeb924554 | ||
|
|
4da3933f24 | ||
|
|
c5703306ef | ||
|
|
a26774b99e | ||
|
|
9258593776 | ||
|
|
48604041e8 | ||
|
|
57ed9ec8e2 | ||
|
|
801ab611ed | ||
|
|
bc34167c84 | ||
|
|
decd0dc035 | ||
|
|
9ac9c693ad | ||
|
|
9b2cd69c0f | ||
|
|
b3f1a19db6 | ||
|
|
f3b6708a92 | ||
|
|
8848885d9a | ||
|
|
c1cab6789e | ||
|
|
907777eeb0 | ||
|
|
7889612edc | ||
|
|
e81e264988 | ||
|
|
eacc29ded0 | ||
|
|
ea04c93bfd | ||
|
|
8692977585 | ||
|
|
6a40f3ed60 | ||
|
|
dd1f631d9d | ||
|
|
15874ac45c | ||
|
|
761fc74a67 | ||
|
|
0e2239e50b | ||
|
|
e9a17517d3 | ||
|
|
94254e61c1 | ||
|
|
9f403a4d6b | ||
|
|
55792d5528 | ||
|
|
a3f726baa8 | ||
|
|
ebc2b23c3a | ||
|
|
e4ca3609d9 | ||
|
|
bc092d8d78 | ||
|
|
dd5933b048 | ||
|
|
5d6128b25c | ||
|
|
24cb04c346 | ||
|
|
f1b54cf0a4 | ||
|
|
e64a7b87a8 | ||
|
|
2b452ea3e8 | ||
|
|
66c6c6c7d1 | ||
|
|
5b4aa1afc2 | ||
|
|
89205276ab | ||
|
|
6d2ab6a7d6 | ||
|
|
e6da910ee2 | ||
|
|
2100ac3cfc | ||
|
|
c7476a1d96 | ||
|
|
d8c3033941 | ||
|
|
7e26ee5a73 | ||
|
|
a8e25ccfe6 | ||
|
|
b6267ec7c2 | ||
|
|
b6bd2884d5 | ||
|
|
767a235611 | ||
|
|
620fc06b6c | ||
|
|
0fa4c89a1b | ||
|
|
1bf046c142 | ||
|
|
52f8429218 | ||
|
|
932b414063 | ||
|
|
097b2390db | ||
|
|
ca8d252ad7 | ||
|
|
23a0dbe3cc | ||
|
|
545ece82b3 | ||
|
|
eaea947b74 | ||
|
|
f1b61d5882 | ||
|
|
e466d72058 | ||
|
|
385be35ed5 | ||
|
|
528b9b6a60 | ||
|
|
dd374eaebf | ||
|
|
9ea483d1dc | ||
|
|
b1813df61a | ||
|
|
8715f74d29 | ||
|
|
152224944b | ||
|
|
f86d12c8f4 | ||
|
|
94d4bc4bac | ||
|
|
c95488549d | ||
|
|
39613aa2d9 | ||
|
|
7c2aafd4ee | ||
|
|
e834c7fe3e | ||
|
|
f96958adf8 | ||
|
|
776074b24f | ||
|
|
c9d64d75f3 | ||
|
|
9651689bb8 | ||
|
|
75be0475ba | ||
|
|
e130b58b20 | ||
|
|
e44f0c497f | ||
|
|
2d0f96d28b | ||
|
|
34d1f79777 | ||
|
|
2185ccd4ea | ||
|
|
125634759d | ||
|
|
350e636e3d | ||
|
|
429140df97 | ||
|
|
a921deafd1 | ||
|
|
071fba2f71 | ||
|
|
9de729e3e7 | ||
|
|
7cf5bd30f2 | ||
|
|
e6cee2965a | ||
|
|
af2b263bc7 | ||
|
|
aa120e0478 | ||
|
|
b07c55a0d9 | ||
|
|
e7f1f496c5 | ||
|
|
823c0434eb | ||
|
|
22162635e7 | ||
|
|
8be0031602 | ||
|
|
29c5e74d31 | ||
|
|
3c8867a1e8 | ||
|
|
c439fe0437 | ||
|
|
b21db670b4 | ||
|
|
1f84aa9809 | ||
|
|
4ac249c26c | ||
|
|
85a29fce94 | ||
|
|
71ecb470b6 | ||
|
|
15a000bb45 | ||
|
|
18e4a7ac6e | ||
|
|
d0322f5fbd | ||
|
|
c1f01b7e35 | ||
|
|
71064f481b | ||
|
|
436293713b | ||
|
|
fc726bfb4b | ||
|
|
b0c3780667 | ||
|
|
3e431c65be | ||
|
|
5b0b90d1f5 | ||
|
|
d16714e84b | ||
|
|
1d5fff9f58 | ||
|
|
fbe8d6144a | ||
|
|
d5f59a57bf | ||
|
|
7465c79884 | ||
|
|
769195fcff | ||
|
|
dc786bd1cc | ||
|
|
960f4ed649 | ||
|
|
91ad3bf1b6 | ||
|
|
91b495d526 | ||
|
|
973d91d120 | ||
|
|
bf5deace8e | ||
|
|
0e4acf6299 | ||
|
|
a5cd0061c5 | ||
|
|
630e3903fa | ||
|
|
0b6a5fad70 | ||
|
|
67ca1b82cc | ||
|
|
9866053f0c | ||
|
|
89a2c1a09c | ||
|
|
70220d8b9c | ||
|
|
274f69526f | ||
|
|
d7026fe36b | ||
|
|
b9b65d7dfb | ||
|
|
1545c78d05 | ||
|
|
f0c292e77b | ||
|
|
62336127e3 | ||
|
|
5beaf8ac98 | ||
|
|
9efd484e27 | ||
|
|
44d5cf980a | ||
|
|
e53650d6c6 | ||
|
|
5bf9a9828c | ||
|
|
24f3bc9f0c | ||
|
|
c200e55f95 | ||
|
|
ea19d59fca | ||
|
|
d34d14c1f4 | ||
|
|
7b17306dbd | ||
|
|
6731564c2d | ||
|
|
194ba0cf8d | ||
|
|
6fc2429540 | ||
|
|
bdcbe61273 | ||
|
|
de5d7bfbd3 | ||
|
|
242878c45c | ||
|
|
c0911da887 | ||
|
|
6e0bf04276 | ||
|
|
56c460d932 | ||
|
|
f0933b66a9 | ||
|
|
422d633f89 | ||
|
|
0537be129c | ||
|
|
9b947c8370 | ||
|
|
14eb4326e7 | ||
|
|
89a3e8fcc7 | ||
|
|
6fd5133bed | ||
|
|
e010877490 | ||
|
|
f56371c79b | ||
|
|
c98f3c5d29 | ||
|
|
5c8de9d82f | ||
|
|
b9c8b6ba23 | ||
|
|
6cd968b53b | ||
|
|
2aa76d257c | ||
|
|
32c0be8bde | ||
|
|
88d283a89d | ||
|
|
66b370c421 | ||
|
|
20bf139b3f | ||
|
|
1da4602567 | ||
|
|
e7ef69e6e7 | ||
|
|
d55904d4db | ||
|
|
740dc59255 | ||
|
|
98b6362c07 | ||
|
|
cd829c096b | ||
|
|
f127c55802 | ||
|
|
13247a0e00 | ||
|
|
609752d331 | ||
|
|
413410d02d | ||
|
|
3528610a51 | ||
|
|
59ee045c24 | ||
|
|
b1dec12893 | ||
|
|
319b0acdd8 | ||
|
|
c605c46f83 | ||
|
|
9ef692b48c | ||
|
|
6da4dfe605 | ||
|
|
7b4cb31a10 | ||
|
|
03ce4d7e2b | ||
|
|
f55f5fa92a | ||
|
|
76757ad1f2 | ||
|
|
347e88dc65 | ||
|
|
746d032e58 | ||
|
|
b6d598a001 | ||
|
|
b35961c53c | ||
|
|
47fba5827b | ||
|
|
47f75ad8bf | ||
|
|
516167c0f8 | ||
|
|
238b3a97a8 | ||
|
|
d4ab8a5a5d | ||
|
|
6672299f8a | ||
|
|
ea5f515f18 | ||
|
|
ea6293544d | ||
|
|
cbe35281b9 | ||
|
|
51a0fc45e2 | ||
|
|
1e7e2bd34f | ||
|
|
fa2f3d136f | ||
|
|
92b6026695 | ||
|
|
c9a5f21344 | ||
|
|
0174bf3722 | ||
|
|
0d003e7450 | ||
|
|
8847838c43 | ||
|
|
9594ce9a8a | ||
|
|
4a91d09c86 | ||
|
|
06837bd32b | ||
|
|
b8d8887d5a | ||
|
|
256f8dd41b | ||
|
|
e0fdafc7e5 | ||
|
|
9a55df245f | ||
|
|
9800d95c50 | ||
|
|
c340416c94 | ||
|
|
9af8a1d30c | ||
|
|
4da96ee980 | ||
|
|
21637e033c | ||
|
|
9ebf2dc97b | ||
|
|
a04689b784 | ||
|
|
5066945adc | ||
|
|
e945c12856 | ||
|
|
0b062d0b8a | ||
|
|
9cc1eff15c | ||
|
|
327e5d06e1 | ||
|
|
a2dd0aea92 | ||
|
|
39da3459c7 | ||
|
|
c0be4c36e1 | ||
|
|
31e04378cd | ||
|
|
e80c99ad74 | ||
|
|
d9be443e53 | ||
|
|
6db323b15e | ||
|
|
5abbfd3f19 | ||
|
|
674215e9e6 | ||
|
|
dce6a5763d | ||
|
|
d89d6e8a01 | ||
|
|
6230dbed2d | ||
|
|
9641254443 | ||
|
|
95871fe13c | ||
|
|
0cecfceb14 | ||
|
|
13970280d9 | ||
|
|
55ce80aabe | ||
|
|
9536a490b3 | ||
|
|
405e07f0a2 | ||
|
|
d3ce91bd89 | ||
|
|
eb44201c5f | ||
|
|
73248aadd5 | ||
|
|
f6a4084f81 | ||
|
|
d5f89c165a | ||
|
|
a518471a27 | ||
|
|
dce5080e53 | ||
|
|
2221d4d612 | ||
|
|
5f73a46c05 | ||
|
|
b782c6bd16 | ||
|
|
ab8d8aa552 | ||
|
|
f955276694 | ||
|
|
77cc60faf2 | ||
|
|
a6f50b8c85 | ||
|
|
e2dfa1d72f | ||
|
|
9a61c0a6fc | ||
|
|
e10b25a12c | ||
|
|
0c1e803208 | ||
|
|
b57dcc74d1 | ||
|
|
f8c583636c | ||
|
|
e6521d1cf3 | ||
|
|
96785e8df1 | ||
|
|
d689778465 | ||
|
|
3c8f8b76aa | ||
|
|
c123fa5422 | ||
|
|
0ade8be7f7 | ||
|
|
a60c2f38c6 | ||
|
|
f1c0797780 | ||
|
|
701167bc12 | ||
|
|
a39e63e324 | ||
|
|
8401e9c2b4 | ||
|
|
c5fca0a1e7 | ||
|
|
e779335d06 | ||
|
|
26039adf5b | ||
|
|
c88286556a | ||
|
|
831b9d4433 | ||
|
|
e937e8fff9 | ||
|
|
f616b2d49a | ||
|
|
fe84dae313 | ||
|
|
9104933b18 | ||
|
|
79654635d3 | ||
|
|
f0edfca75c | ||
|
|
e845da2edc | ||
|
|
7a3050f2c0 | ||
|
|
9a6531e2a2 | ||
|
|
a6a17a85f3 | ||
|
|
9275fd16c2 | ||
|
|
904ae05810 | ||
|
|
54f95389a8 | ||
|
|
a8fc70a5b9 | ||
|
|
c374072822 | ||
|
|
0212de68a4 | ||
|
|
2ea9b6d409 | ||
|
|
823d71df28 | ||
|
|
7560918b32 | ||
|
|
fd87faa7a6 | ||
|
|
cb2d706fa1 | ||
|
|
6b638ac896 | ||
|
|
2bd5ae3617 | ||
|
|
39a5311315 | ||
|
|
9b6e46dc6b | ||
|
|
7311d1182d | ||
|
|
ea1d8b8104 | ||
|
|
fb03e3f00e | ||
|
|
c9c35255e7 | ||
|
|
99a578dbad | ||
|
|
e56c0a6251 | ||
|
|
66479e2aa7 | ||
|
|
6feddcbced | ||
|
|
db020ca1a3 | ||
|
|
6c93518ef7 | ||
|
|
eb02d01eed | ||
|
|
7a9093f634 | ||
|
|
1732b2dfe3 | ||
|
|
a62f891a60 | ||
|
|
a22ecd42ed | ||
|
|
b7cb2a2951 | ||
|
|
c490970324 | ||
|
|
5a9c8a9343 | ||
|
|
5ba7e5d7d7 | ||
|
|
f7b281a65f | ||
|
|
df5a1c59e6 | ||
|
|
0615709a7a | ||
|
|
d85a0130b7 | ||
|
|
71f17a233e | ||
|
|
25c35cbbe4 | ||
|
|
257ba570ee | ||
|
|
91e96b2314 | ||
|
|
c2ee7cbff5 | ||
|
|
27f813e043 | ||
|
|
00ed91f12e | ||
|
|
4cb5efc277 | ||
|
|
65a453d21b | ||
|
|
9c8cb4dea3 | ||
|
|
ed902fdb70 | ||
|
|
509067391b | ||
|
|
04b261057d | ||
|
|
852343f254 | ||
|
|
26e35344d0 | ||
|
|
d3a619659f | ||
|
|
979f2415fb | ||
|
|
28c1d219f6 | ||
|
|
5792f4bf07 | ||
|
|
3a0fa5cb29 | ||
|
|
074ee656f0 | ||
|
|
064f93185c | ||
|
|
4b5922f652 | ||
|
|
85be906b68 | ||
|
|
775285cdf8 | ||
|
|
42f96dc7a6 | ||
|
|
e96fa64625 | ||
|
|
8dc495c9bc | ||
|
|
5d70d889e9 | ||
|
|
999ae6eb49 | ||
|
|
ae1450bbcf | ||
|
|
dcd8a05809 | ||
|
|
62e466f774 | ||
|
|
70777a047d | ||
|
|
47fd95db9d | ||
|
|
7602d9e54b | ||
|
|
1ed0079882 | ||
|
|
b026be410c | ||
|
|
767a1711ff | ||
|
|
a93bd8d944 | ||
|
|
4e12f86e90 | ||
|
|
3007009fab | ||
|
|
2d886b65ce | ||
|
|
8700b87030 | ||
|
|
5a46f1229d | ||
|
|
9d5f8883a7 | ||
|
|
8e0b9b82e9 | ||
|
|
ea4b4ddce4 | ||
|
|
bd95c7b82a | ||
|
|
e20c5cf9cf | ||
|
|
6adb489cb3 | ||
|
|
0c2db1cea5 | ||
|
|
e33604887b | ||
|
|
410f37df1b | ||
|
|
c9f3883c8c | ||
|
|
4346d7605d | ||
|
|
a0a2c27973 | ||
|
|
3fb87ee76e | ||
|
|
242aeea24c | ||
|
|
c305dc8d22 | ||
|
|
f61b898633 | ||
|
|
2bdcd436bb | ||
|
|
a1bea7d7cc | ||
|
|
b2bdc73164 | ||
|
|
cbaf0a3864 | ||
|
|
103563b375 | ||
|
|
595429fdde | ||
|
|
b384b27546 | ||
|
|
0b996245d5 | ||
|
|
1ee91dd690 | ||
|
|
f9e602c44c | ||
|
|
4fa827ddfd | ||
|
|
1b3c73618c | ||
|
|
7b08f1cc8c | ||
|
|
7d392e5adb | ||
|
|
f44cc2b60c | ||
|
|
31680898e3 | ||
|
|
318fd7c9e3 | ||
|
|
b10b8ca3f4 | ||
|
|
b0c33308be | ||
|
|
1421c4e9d3 | ||
|
|
f55dfc9025 | ||
|
|
c218970890 | ||
|
|
bd27ce2520 | ||
|
|
44795b65f9 | ||
|
|
af84c4e6bd | ||
|
|
0a28207200 | ||
|
|
8ca2a5832c | ||
|
|
333534dfe7 | ||
|
|
d8ce0d0df0 | ||
|
|
28c3259449 | ||
|
|
0d0ede7b14 | ||
|
|
9ebf6bcc92 | ||
|
|
9d186e9ba3 | ||
|
|
3c3a4526bf | ||
|
|
3094c2ce17 | ||
|
|
393494a728 | ||
|
|
d2725c3f49 | ||
|
|
4d4425a5bf | ||
|
|
c11fbe0868 | ||
|
|
c676689df0 | ||
|
|
0f5625d721 | ||
|
|
6f5e6bd0f1 | ||
|
|
a0af092ecb | ||
|
|
3a07a194ab | ||
|
|
682ffa7cf5 | ||
|
|
dc4a4ca9d3 | ||
|
|
33ac85f637 | ||
|
|
efd9421dc9 | ||
|
|
9b696a872b | ||
|
|
aab515b16c | ||
|
|
f220628354 | ||
|
|
322bc5dc87 | ||
|
|
75c3bda866 | ||
|
|
b2b776169b | ||
|
|
8e8d7ae614 | ||
|
|
fa1af5a2cb | ||
|
|
a27e4072b4 | ||
|
|
fad26a49be | ||
|
|
1742159345 | ||
|
|
ed8d2cb482 | ||
|
|
8e1f022810 | ||
|
|
4c25072c18 | ||
|
|
564ec32520 | ||
|
|
a743feb040 | ||
|
|
b028667de1 | ||
|
|
41888f84bc | ||
|
|
6a918dbde9 | ||
|
|
578230e32c | ||
|
|
d486b03089 | ||
|
|
8559334339 | ||
|
|
968c6ed8be | ||
|
|
8893d9edc4 | ||
|
|
43753ec113 | ||
|
|
2ec3e4a912 | ||
|
|
a086745ec0 | ||
|
|
51156d0582 | ||
|
|
ea9925f489 | ||
|
|
026b96b8f2 | ||
|
|
136b2ae37f | ||
|
|
97009a2748 | ||
|
|
e123f7c743 | ||
|
|
e28bde6ccd | ||
|
|
a976f418e3 | ||
|
|
3c701e780c | ||
|
|
769dd174bd | ||
|
|
e92514ee63 | ||
|
|
8ebc517b41 | ||
|
|
91b03e52f1 | ||
|
|
a22406c9f8 | ||
|
|
ebc3666c6f | ||
|
|
f1fee1239b | ||
|
|
8769fa0156 | ||
|
|
f4d7338687 | ||
|
|
6a8c3f82ef | ||
|
|
05bcbfa28c | ||
|
|
6a55500c1b | ||
|
|
a5a5ac60ba | ||
|
|
6ed7f47b3f | ||
|
|
a3e94855f9 | ||
|
|
503da97a79 | ||
|
|
088a93e023 | ||
|
|
30f71ad632 | ||
|
|
0026849821 | ||
|
|
cf5a310286 | ||
|
|
72384ff2cb | ||
|
|
c33ef01af8 | ||
|
|
11116bdcb7 | ||
|
|
09a5cf4e68 | ||
|
|
a9172129d2 | ||
|
|
3ec06705ca | ||
|
|
5fb0d38ad8 | ||
|
|
9ed5cddb89 | ||
|
|
4e97fb0e58 | ||
|
|
1688e373bc | ||
|
|
cada0b6df1 | ||
|
|
91358010a0 | ||
|
|
51024d3821 | ||
|
|
220d6ed494 | ||
|
|
b5ed3edc8f | ||
|
|
73c96f35c1 | ||
|
|
b8d79d9132 | ||
|
|
507c71f64c | ||
|
|
ce0067d8eb | ||
|
|
c0b238b19a | ||
|
|
d961cf21fb | ||
|
|
1f7622e4c4 | ||
|
|
04fe7e61de | ||
|
|
3e6607585f | ||
|
|
0b2213dd41 | ||
|
|
08725c44c6 | ||
|
|
75a66b716e | ||
|
|
0c05e6593e | ||
|
|
c43ab50d66 | ||
|
|
26e7da0b96 | ||
|
|
98b1c7a38c | ||
|
|
ccdbec619c | ||
|
|
47001c3303 | ||
|
|
8e50fecccc | ||
|
|
938fcdd1a6 | ||
|
|
9ede57b228 | ||
|
|
e074d02714 | ||
|
|
e26de9c1d1 | ||
|
|
7dc3835a54 | ||
|
|
117a8cafca | ||
|
|
8a0a0aef5c | ||
|
|
4750e15c20 | ||
|
|
747ce9b1f1 | ||
|
|
7fa874d9ef | ||
|
|
5febc3e07d | ||
|
|
2244bf2ba2 | ||
|
|
29cb62af3d | ||
|
|
f92d2e3f7c | ||
|
|
a9b75d059b | ||
|
|
e6f289deb6 | ||
|
|
0e22618d93 | ||
|
|
c5bb074573 | ||
|
|
4e8fc6d198 | ||
|
|
618d673947 | ||
|
|
4cd5529027 | ||
|
|
5ac08ec3aa |
103
.gitlab-ci.yml
103
.gitlab-ci.yml
@@ -1,8 +1,7 @@
|
||||
# Select image from https://hub.docker.com/_/php/
|
||||
#image: php:7.2
|
||||
# Use a prepared Hubzilla image to optimise pipeline run
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.2
|
||||
|
||||
#image: php:7.3
|
||||
# Use a prepared Hubzilla image to optimise pipeline duration
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
|
||||
stages:
|
||||
- test
|
||||
@@ -32,55 +31,29 @@ 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
|
||||
- docker-php-ext-enable xdebug
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php composer.phar install --no-progress
|
||||
- php ./composer.phar install --no-progress
|
||||
# php.ini settings
|
||||
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
|
||||
|
||||
|
||||
# test PHP7 with MySQL 5.7
|
||||
php7.2_mysql 1/2:
|
||||
# hidden job definition with template for MySQL/MariaDB
|
||||
.job_template_mysql: &job_definition_mysql
|
||||
stage: test
|
||||
services:
|
||||
- mysql:5.7
|
||||
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
|
||||
|
||||
|
||||
# test PHP7 with MySQL latest (8)
|
||||
php7.2_mysql 2/2:
|
||||
stage: test
|
||||
services:
|
||||
- name: mysql:latest
|
||||
command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
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
|
||||
|
||||
|
||||
# test PHP7 with MariaDB latest (10.3)
|
||||
php7.2_mariadb:
|
||||
stage: test
|
||||
services:
|
||||
- name: mariadb:latest
|
||||
alias: mysql
|
||||
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
|
||||
|
||||
|
||||
# test PHP7 with PostgreSQL latest
|
||||
php7.2_postgres:
|
||||
# hidden job definition with template for PostgreSQL
|
||||
.job_template_postgres: &job_definition_postgres
|
||||
stage: test
|
||||
services:
|
||||
- postgres:latest
|
||||
@@ -95,7 +68,10 @@ php7.2_postgres:
|
||||
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
|
||||
# Run the actual tests
|
||||
- vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
|
||||
artifacts:
|
||||
|
||||
# hidden job definition with artifacts config template
|
||||
.artifacts_template:
|
||||
artifacts: &artifacts_template
|
||||
expire_in: 1 week
|
||||
# Gitlab should show the results, but has problems parsing PHPUnit's junit file.
|
||||
reports:
|
||||
@@ -106,7 +82,52 @@ php7.2_postgres:
|
||||
- tests/results/
|
||||
|
||||
|
||||
# Generate Doxygen API Documentation and deploy it at GitLab pages
|
||||
# PHP7.3 with MySQL 5.7
|
||||
php7.3_mysql5.7:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- mysql:5.7
|
||||
|
||||
|
||||
# PHP7.3 with MySQL 8 (latest)
|
||||
php7.3_mysql8:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- name: mysql:8
|
||||
command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
|
||||
|
||||
# PHP7.3 with MariaDB 10.2
|
||||
php7.3_mariadb10.2:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- name: mariadb:10.2
|
||||
alias: mysql
|
||||
|
||||
|
||||
# PHP7.3 with MariaDB 10.3 (latest)
|
||||
php7.3_mariadb10.3:
|
||||
<<: *job_definition_mysql
|
||||
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
|
||||
|
||||
|
||||
# Generate Doxygen API Documentation and deploy it as GitLab pages
|
||||
pages:
|
||||
stage: deploy
|
||||
cache: {}
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
# Hubzilla at Home next to your Router
|
||||
|
||||
Run hubzilla-setup.sh for an unattended installation of hubzilla.
|
||||
|
||||
The script is known to work without adjustments with
|
||||
|
||||
+ Hardware
|
||||
- Mini-PC with Debian-9.5-amd64, or
|
||||
- Rapberry 3 with Raspbian, Debian-9.5
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
- freedns.afraid.org
|
||||
# How to use
|
||||
|
||||
## Disclaimers
|
||||
|
||||
- This script does work with Debian 9 only.
|
||||
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
|
||||
|
||||
# Step-by-Step Overwiew
|
||||
- This script does work with Debian 10 only.
|
||||
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation). You may use it to install several hub/instances on the same server, though.
|
||||
|
||||
## Preconditions
|
||||
|
||||
@@ -28,97 +16,99 @@ Hardware
|
||||
|
||||
Software
|
||||
|
||||
+ Fresh installation of Debian 9 (Stretch)
|
||||
+ Router with open ports 80 and 443 for your Hub
|
||||
+ Fresh installation of Debian 10 (Buster)
|
||||
+ Router with open ports 80 and 443 for your web server
|
||||
|
||||
## The basic steps (quick overview)
|
||||
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
|
||||
- git clone https://framagit.org/hubzilla/core.git html (you can replace "html" with any folder name you like, which you'll have to do if you plan to have more than one hub/instance running on your server)
|
||||
- cd html/.homeinstall
|
||||
- cp hubzilla-config.txt.template hubzilla-config.txt
|
||||
- nano hubzilla-config.txt
|
||||
- cp zotserver-config.txt.template zotserver-config.txt
|
||||
- nano zotserver-config.txt
|
||||
- Read the comments carefully
|
||||
- Enter your values: db pass, domain, values for dyn DNS
|
||||
- Make sure your external drive (for backups) is mounted
|
||||
- hubzilla-setup.sh as root
|
||||
- ... wait, wait, wait until the script is finised
|
||||
- reboot
|
||||
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If the check of the mail address fails when you try to register the very first user in the browser. Do...
|
||||
|
||||
cd /var/www/html
|
||||
util/config system.do_not_check_dns 1
|
||||
- Prepare your external disk for backups
|
||||
- ./zotserver-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 hub/instance.
|
||||
|
||||
## Optional - Set path to imagemagick
|
||||
|
||||
In Admin settings of hubzilla or via terminal
|
||||
In Admin settings of your hub/instance or via terminal
|
||||
|
||||
cd /var/www/html
|
||||
cd /var/www/html (or the custom path you chose)
|
||||
util/config system.imagick_convert_path /usr/bin/convert
|
||||
|
||||
# Step-by-Step in Detail
|
||||
## Optional - Switch verification of email on/off
|
||||
|
||||
## Preparations Hardware
|
||||
Do this just before you register the first user.
|
||||
|
||||
### Mini-PC
|
||||
In Admin settings of your hub/instance or via terminal
|
||||
|
||||
### Recommended: USB Drive for Backups
|
||||
cd /var/www/html
|
||||
|
||||
The installation will create a daily backup written to an external drive.
|
||||
Check the current setting
|
||||
|
||||
The USB drive must be compatible with the filesystems
|
||||
util/config system verify_email
|
||||
|
||||
- ext4 (if you do not want to encrypt the USB)
|
||||
- LUKS + ext4 (if you want to encrypt the USB)
|
||||
Switch the verification on/off (1/0)
|
||||
|
||||
The backup includes
|
||||
util/config system verify_email 0
|
||||
|
||||
- Hubzilla DB
|
||||
- Hubzilla installation /var/www/html
|
||||
- Certificates for letsencrypt
|
||||
## What the script will do for you...
|
||||
|
||||
## Preparations Software
|
||||
+ install everything required by your hub/instance, basically a web server (Apache or Nginx), PHP, a database (MySQL), certbot,...
|
||||
+ create a database
|
||||
+ run certbot to have everything for a secure connection (httpS)
|
||||
+ create a script for daily maintenance
|
||||
- backup to external disk (certificates, database, /var/www/)
|
||||
- renew certfificate (letsencrypt)
|
||||
- update of your hub/instance (git)
|
||||
- update of Debian
|
||||
- restart
|
||||
+ create cron jobs for
|
||||
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
|
||||
- Run.php for your hub/instance every 10 minutes
|
||||
- daily maintenance script every day at 05:30
|
||||
|
||||
### Install Debian Linux on the Mini-PC
|
||||
The script is known to work without adjustments with
|
||||
|
||||
Download the stable Debian at https://www.debian.org/
|
||||
(Debian 8 is no longer supported.)
|
||||
+ Hardware
|
||||
- Mini-PC with Debian 10 (stretch), or
|
||||
- Rapberry 3 with Raspbian, Debian 10
|
||||
- Rapberry 4 with Raspbian, Debian 10
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
- freedns.afraid.org
|
||||
|
||||
Create bootable USB drive with Debian on it.You could use
|
||||
|
||||
- unetbootin, https://en.wikipedia.org/wiki/UNetbootin
|
||||
- or simply the linux command "dd"
|
||||
|
||||
Example for command dd...
|
||||
|
||||
su -
|
||||
dd if=2018-10-09-raspbian-stretch.img of=/dev/mmcblk0
|
||||
|
||||
Do not forget to unmount the SD card before and check if unmounted like in this example...
|
||||
|
||||
su -
|
||||
umount /dev/mmcblk0*
|
||||
df -h
|
||||
The script can install [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project), [Zap](https://zotlabs.com/zap/) and [Mistpark 2020, aka "Misty"](https://zotlabs.com/misty/). Make sure to use the correct GIT repositories.
|
||||
|
||||
|
||||
Switch off your mini pc, plug in your USB drive and start the mini pc from the
|
||||
stick. Install Debian. Follow the instructions of the installation.
|
||||
# Step-by-Step - some Details
|
||||
|
||||
### Configure your Router
|
||||
## Preparations
|
||||
|
||||
Open the ports 80 and 443 on your router for your Debian
|
||||
## 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
|
||||
|
||||
Your Hubzilla must be reachable by a domain that you can type in your browser
|
||||
Follow the instructions in .homeinstall/zotserver-config.txt.
|
||||
|
||||
In short...
|
||||
|
||||
Your Hubzilla server must be reachable by a domain that you can type in your browser
|
||||
|
||||
cooldomain.org
|
||||
|
||||
@@ -132,105 +122,13 @@ There are two ways to get a domain...
|
||||
|
||||
...for example buy at selfHOST.de
|
||||
|
||||
The cost are around 10,- € once and 1,50 € per month (2017).
|
||||
The cost is 1,50 € per month (2019).
|
||||
|
||||
### Method 2: Register a free subdomain
|
||||
|
||||
...for example register at freedns.afraid.org
|
||||
|
||||
Follow the instructions in .homeinstall/hubzilla-config.txt.
|
||||
|
||||
|
||||
## Install Hubzilla on your Debian
|
||||
|
||||
Login to your debian
|
||||
(Provided your username is "you" and the name of the mini pc is "debian". You
|
||||
could take the IP address instead of "debian")
|
||||
|
||||
ssh -X you@debian
|
||||
|
||||
Change to root user
|
||||
|
||||
su -l
|
||||
|
||||
Install git
|
||||
|
||||
apt-get install git
|
||||
|
||||
Make the directory for apache and change diretory to it
|
||||
|
||||
mkdir /var/www
|
||||
cd /var/www/
|
||||
|
||||
Clone hubzilla from git ("git pull" will update it later)
|
||||
|
||||
git clone https://framagit.org/hubzilla/core.git html
|
||||
|
||||
Change to the install script
|
||||
|
||||
cd html/.homeinstall/
|
||||
|
||||
Copy the template file
|
||||
|
||||
cp hubzilla-config.txt.template hubzilla-config.txt
|
||||
|
||||
Modify the file "hubzilla-config.txt". Read the instructions there carefully and enter your values.
|
||||
|
||||
nano hubzilla-config.txt
|
||||
|
||||
Make sure your external drive (for backups) is plugged in and can be mounted as configured in "hubzilla-config.txt". Otherwise the daily backups will not work.
|
||||
|
||||
Run the script
|
||||
|
||||
./hubzilla-setup.sh
|
||||
|
||||
Wait... The script should not finish with an error message.
|
||||
|
||||
In a webbrowser open your domain.
|
||||
Expected: A test page of hubzilla is shown. All checks there should be
|
||||
successfull. Go on...
|
||||
Expected: A page for the Hubzilla server configuration shows up.
|
||||
|
||||
Leave db server name "127.0.0.1" and port "0" untouched.
|
||||
|
||||
Enter
|
||||
|
||||
- DB user name = hubzilla
|
||||
- DB pass word = This is the password you entered in "hubzilla-config.txt"
|
||||
- DB name = hubzilla
|
||||
|
||||
Leave db type "MySQL" untouched.
|
||||
|
||||
Follow the instructions in the next pages.
|
||||
|
||||
Recommended: Set path to imagemagick
|
||||
|
||||
- in admin settings of hubzilla or
|
||||
- via terminal
|
||||
|
||||
util/config system.imagick_convert_path /usr/bin/convert
|
||||
|
||||
After the daily script was executed at 05:30 (am)
|
||||
|
||||
- look at /var/www/html/hubzilla-daily.log
|
||||
- check your backup on the external drive
|
||||
- optionally view the daily log under yourdomain.org/admin/logs/
|
||||
- set the logfile to var/www/html/hubzilla-daily.log
|
||||
|
||||
|
||||
## Install Hubzilla in a Virtual Machine for Test Purposes
|
||||
|
||||
Modify the file "hubzilla-config.txt".
|
||||
|
||||
nano hubzilla-config.txt
|
||||
|
||||
There use
|
||||
|
||||
le_domain=localhost
|
||||
|
||||
## Note for the Rasperry
|
||||
|
||||
The script was tested with an Raspberry 3 under Raspian (Debian 9.5, 2018-10-09-raspbian-stretch.img).
|
||||
## Note on Rasperry
|
||||
|
||||
It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
@@ -240,12 +138,6 @@ to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
If the validation of the mail address fails for the very first registered user...
|
||||
This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
|
||||
|
||||
So if your system isn't registered in DNS or DNS isn't active do
|
||||
|
||||
cd /var/www/html
|
||||
util/config system.do_not_check_dns 1
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -1,850 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# How to use
|
||||
# ----------
|
||||
#
|
||||
# This file automates the installation of hubzilla under Debian Linux
|
||||
#
|
||||
# 1) Copy the file "hubzilla-config.txt.template" to "hubzilla-config.txt"
|
||||
# Follow the instuctions there
|
||||
#
|
||||
# 2) Switch to user "root" by typing "su -"
|
||||
#
|
||||
# 3) Run with "./hubzilla-setup.sh"
|
||||
# If this fails check if you can execute the script.
|
||||
# - To make it executable type "chmod +x hubzilla-setup.sh"
|
||||
# - or run "bash hubzilla-setup.sh"
|
||||
#
|
||||
#
|
||||
# What does this script do basically?
|
||||
# -----------------------------------
|
||||
#
|
||||
# This file automates the installation of hubzilla under Debian Linux
|
||||
# - install
|
||||
# * apache webserer,
|
||||
# * php,
|
||||
# * mysql - the database for hubzilla,
|
||||
# * phpmyadmin,
|
||||
# * git to download and update hubzilla itself
|
||||
# - download hubzilla core and addons
|
||||
# - configure cron
|
||||
# * "poller.php" for regular background prozesses of hubzilla
|
||||
# * to_do "apt-get update" and "apt-get dist-upgrade" to keep linux
|
||||
# up-to-date
|
||||
# * to_do backup hubzillas database and files (rsnapshot)
|
||||
# - configure dynamic ip with cron
|
||||
# - to_do letsencrypt
|
||||
# - to_do redirection to https
|
||||
#
|
||||
#
|
||||
# Discussion
|
||||
# ----------
|
||||
#
|
||||
# Security - password is the same for mysql-server, phpmyadmin and hubzilla db
|
||||
# - The script runs into installation errors for phpmyadmin if it uses
|
||||
# different passwords. For the sake of simplicity one singel password.
|
||||
#
|
||||
# Security - suhosin for PHP
|
||||
# - The script does not install suhosin.
|
||||
# - Is the security package suhosin usefull or not usefull?
|
||||
#
|
||||
# Hubzilla - email verification
|
||||
# - The script switches off email verification off in all htconfig.tpl.
|
||||
# Example: /var/www/html/view/en/htconfig.tpl
|
||||
# - Is this a silly idea or not?
|
||||
#
|
||||
#
|
||||
# Remove Hubzilla (for a fresh start using the script)
|
||||
# ----------------------------------------------------
|
||||
#
|
||||
# You could use /var/www/hubzilla-remove.sh
|
||||
# that is created by hubzilla-setup.sh.
|
||||
#
|
||||
# The script will remove (almost everything) what was installed by the script.
|
||||
# After the removal you could run the script again to have a fresh install
|
||||
# of all applications including hubzilla and its database.
|
||||
#
|
||||
# How to restore from backup
|
||||
# --------------------------
|
||||
#
|
||||
# Daily backup
|
||||
# - - - - - -
|
||||
#
|
||||
# The installation
|
||||
# - writes a script /var/www/hubzilla-daily.sh
|
||||
# - creates a daily cron that runs the hubzilla-daily.sh
|
||||
#
|
||||
# hubzilla-daily.sh makes a (daily) backup of all relevant files
|
||||
# - /var/lib/mysql/ > hubzilla database
|
||||
# - /var/www/html/ > hubzilla from github
|
||||
# - /var/www/letsencrypt/ > certificates
|
||||
#
|
||||
# hubzilla-daily.sh writes the backup
|
||||
# - either to an external disk compatible to LUKS+ext4 (see hubzilla-config.txt)
|
||||
# - or to /var/cache/rsnapshot in case the external disk is not plugged in
|
||||
#
|
||||
# Restore backup
|
||||
# - - - - - - -
|
||||
#
|
||||
# This was not tested yet.
|
||||
# Bacically you can copy the files from the backup to the server.
|
||||
#
|
||||
# Credits
|
||||
# -------
|
||||
#
|
||||
# The script is based on Thomas Willinghams script "debian-setup.sh"
|
||||
# which he used to install the red#matrix.
|
||||
#
|
||||
# The script uses another script from https://github.com/lukas2511/letsencrypt.sh
|
||||
#
|
||||
# The documentation for bash is here
|
||||
# https://www.gnu.org/software/bash/manual/bash.html
|
||||
#
|
||||
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 9' /etc/issue
|
||||
then
|
||||
die "Linux 9 (stretch) 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
|
||||
# backup is important and should be checked
|
||||
if [ -n "$backup_device_name" ]
|
||||
then
|
||||
if [ ! -d "$backup_mount_point" ]
|
||||
then
|
||||
mkdir "$backup_mount_point"
|
||||
fi
|
||||
device_mounted=0
|
||||
if fdisk -l | grep -i "$backup_device_name.*linux"
|
||||
then
|
||||
print_info "ok - filesystem of external device is linux"
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo "$backup_device_pass" | cryptsetup luksOpen $backup_device_name cryptobackup
|
||||
if mount /dev/mapper/cryptobackup /media/hubzilla_backup
|
||||
then
|
||||
device_mounted=1
|
||||
print_info "ok - could encrypt and mount external backup device"
|
||||
umount /media/hubzilla_backup
|
||||
else
|
||||
print_warn "backup to external device will fail because encryption failed"
|
||||
fi
|
||||
cryptsetup luksClose cryptobackup
|
||||
else
|
||||
if mount $backup_device_name /media/hubzilla_backup
|
||||
then
|
||||
device_mounted=1
|
||||
print_info "ok - could mount external backup device"
|
||||
umount /media/hubzilla_backup
|
||||
else
|
||||
print_warn "backup to external device will fail because mount failed"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
print_warn "backup to external device will fail because filesystem is either not linux or 'backup_device_name' is not correct in $configfile"
|
||||
fi
|
||||
if [ $device_mounted == 0 ]
|
||||
then
|
||||
die "backup device not ready"
|
||||
fi
|
||||
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
|
||||
print_info "updated and upgraded linux"
|
||||
}
|
||||
|
||||
function check_install {
|
||||
if [ -z "`which "$1" 2>/dev/null`" ]
|
||||
then
|
||||
# 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 -q -y install $2
|
||||
print_info "installed $2 installed for $1"
|
||||
else
|
||||
print_warn "$2 already installed"
|
||||
fi
|
||||
}
|
||||
|
||||
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_hubzilla {
|
||||
if [ -d /etc/apache2 ]
|
||||
then
|
||||
print_info "stopping apache webserver..."
|
||||
service apache2 stop
|
||||
fi
|
||||
if [ -f /etc/init.d/mysql ]
|
||||
then
|
||||
print_info "stopping mysql db..."
|
||||
/etc/init.d/mysql stop
|
||||
fi
|
||||
}
|
||||
|
||||
function install_apache {
|
||||
print_info "installing apache..."
|
||||
nocheck_install "apache2 apache2-utils"
|
||||
}
|
||||
|
||||
function install_imagemagick {
|
||||
print_info "installing imagemagick..."
|
||||
nocheck_install "imagemagick"
|
||||
}
|
||||
|
||||
function install_curl {
|
||||
print_info "installing curl..."
|
||||
nocheck_install "curl"
|
||||
}
|
||||
|
||||
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-mcrypt php-gd"
|
||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.0/apache2/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.0/apache2/php.ini
|
||||
}
|
||||
|
||||
function install_mysql {
|
||||
# http://www.microhowto.info/howto/perform_an_unattended_installation_of_a_debian_package.html
|
||||
#
|
||||
# To determine the required package name, key and type you can perform
|
||||
# a trial installation then search the configuration database.
|
||||
#
|
||||
# debconf-get-selections | grep mysql-server
|
||||
#
|
||||
# The command debconf-get-selections is provided by the package
|
||||
# debconf-utils, which you may need to install.
|
||||
#
|
||||
# apt-get install debconf-utils
|
||||
#
|
||||
# If you want to supply an answer to a configuration question but do not
|
||||
# want to be prompted for it then this can be arranged by preseeding the
|
||||
# DebConf database with the required information.
|
||||
#
|
||||
# echo mysql-server mysql-server/root_password password xyzzy | debconf-set-selections
|
||||
# echo mysql-server mysql-server/root_password_again password xyzzy | debconf-set-selections
|
||||
#
|
||||
print_info "installing mysql..."
|
||||
if [ -z "$mysqlpass" ]
|
||||
then
|
||||
die "mysqlpass not set in $configfile"
|
||||
fi
|
||||
echo mysql-server mysql-server/root_password password $mysqlpass | debconf-set-selections
|
||||
echo mysql-server mysql-server/root_password_again password $mysqlpass | debconf-set-selections
|
||||
nocheck_install "php-mysql mysql-server mysql-client"
|
||||
}
|
||||
|
||||
function install_phpmyadmin {
|
||||
print_info "installing phpmyadmin..."
|
||||
if [ -z "$phpmyadminpass" ]
|
||||
then
|
||||
die "phpmyadminpass not set in $configfile"
|
||||
fi
|
||||
echo phpmyadmin phpmyadmin/setup-password password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/mysql/app-pass password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/app-password-confirm password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/mysql/admin-pass password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/password-confirm password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2 | debconf-set-selections
|
||||
nocheck_install "phpmyadmin"
|
||||
|
||||
# It seems to be not neccessary to check rewrite.load because it comes
|
||||
# with the installation. To be sure you could check this manually by:
|
||||
#
|
||||
# nano /etc/apache2/mods-available/rewrite.load
|
||||
#
|
||||
# You should find the content:
|
||||
#
|
||||
# LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
|
||||
|
||||
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
|
||||
if [ -z "`grep 'Include /etc/phpmyadmin/apache.conf' /etc/apache2/apache2.conf`" ]
|
||||
then
|
||||
echo "Include /etc/phpmyadmin/apache.conf" >> /etc/apache2/apache2.conf
|
||||
fi
|
||||
service apache2 restart
|
||||
/etc/init.d/mysql start
|
||||
}
|
||||
|
||||
function create_hubzilla_db {
|
||||
print_info "creating hubzilla database..."
|
||||
if [ -z "$hubzilla_db_name" ]
|
||||
then
|
||||
die "hubzilla_db_name not set in $configfile"
|
||||
fi
|
||||
if [ -z "$hubzilla_db_user" ]
|
||||
then
|
||||
die "hubzilla_db_user not set in $configfile"
|
||||
fi
|
||||
if [ -z "$hubzilla_db_pass" ]
|
||||
then
|
||||
die "hubzilla_db_pass not set in $configfile"
|
||||
fi
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$phpmyadminpass -e "$SQL"
|
||||
}
|
||||
|
||||
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 - https://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 https://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
|
||||
echo "*/30 * * * * root wget --no-check-certificate -O - https://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 "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 '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
|
||||
# configure apache
|
||||
apache_le_conf=/etc/apache2/sites-available/le-default.conf
|
||||
if [ -f $apache_le_conf ]
|
||||
then
|
||||
print_info "$apache_le_conf exist already"
|
||||
else
|
||||
cat > $apache_le_conf <<END
|
||||
# letsencrypt default Apache configuration
|
||||
Alias /.well-known/acme-challenge /var/www/letsencrypt
|
||||
|
||||
<Directory /var/www/letsencrypt>
|
||||
Options FollowSymLinks
|
||||
Allow from all
|
||||
</Directory>
|
||||
END
|
||||
a2ensite le-default.conf
|
||||
service apache2 restart
|
||||
fi
|
||||
# download the shell script
|
||||
if [ -d $le_dir ]
|
||||
then
|
||||
print_info "letsenrypt exists already (nothing downloaded > no certificate created and registered)"
|
||||
return 0
|
||||
fi
|
||||
git clone https://github.com/lukas2511/dehydrated $le_dir
|
||||
cd $le_dir
|
||||
# create config file for letsencrypt.sh
|
||||
echo "WELLKNOWN=$le_dir" > $le_dir/config.sh
|
||||
if [ -n "$le_email" ]
|
||||
then
|
||||
echo "CONTACT_EMAIL=$le_email" >> $le_dir/config.sh
|
||||
fi
|
||||
# create domain file for letsencrypt.sh
|
||||
# WATCH THIS:
|
||||
# - It did not work wit "sub.domain.org www.sub.domain.org".
|
||||
# - So just use "sub.domain.org" only!
|
||||
echo "$le_domain" > $le_dir/domains.txt
|
||||
# test apache config for letsencrpyt
|
||||
url_http=http://$le_domain/.well-known/acme-challenge/domains.txt
|
||||
wget_output=$(wget -nv --spider --max-redirect 0 $url_http)
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
die "Failed to load $url_http"
|
||||
fi
|
||||
# accept terms of service of letsencrypt
|
||||
./dehydrated --register --accept-terms
|
||||
# run script dehydrated
|
||||
#
|
||||
./dehydrated --cron --config $le_dir/config.sh
|
||||
}
|
||||
|
||||
function configure_apache_for_https {
|
||||
print_info "configuring apache to use httpS ..."
|
||||
# letsencrypt.sh
|
||||
#
|
||||
# "${BASEDIR}/certs/${domain}/privkey.pem"
|
||||
# "${BASEDIR}/certs/${domain}/cert.pem"
|
||||
# "${BASEDIR}/certs/${domain}/fullchain.pem"
|
||||
#
|
||||
SSLCertificateFile=${le_dir}/certs/${le_domain}/cert.pem
|
||||
SSLCertificateKeyFile=${le_dir}/certs/${le_domain}/privkey.pem
|
||||
SSLCertificateChainFile=${le_dir}/certs/${le_domain}/fullchain.pem
|
||||
if [ ! -f $SSLCertificateFile ]
|
||||
then
|
||||
print_warn "Failed to configure apache for httpS: Missing certificate file $SSLCertificateFile"
|
||||
return 0
|
||||
fi
|
||||
# make sure that the ssl mode is enabled
|
||||
print_info "...configuring apache to use httpS - a2enmod ssl ..."
|
||||
a2enmod ssl
|
||||
# modify apach' ssl conf file
|
||||
if grep -i "ServerName" $sslconf
|
||||
then
|
||||
print_info "seems that apache was already configered to use httpS with $sslconf"
|
||||
else
|
||||
sed -i "s/ServerAdmin.*$/ServerAdmin webmaster@localhost\\n ServerName ${le_domain}/" $sslconf
|
||||
fi
|
||||
sed -i s#/etc/ssl/certs/ssl-cert-snakeoil.pem#$SSLCertificateFile# $sslconf
|
||||
sed -i s#/etc/ssl/private/ssl-cert-snakeoil.key#$SSLCertificateKeyFile# $sslconf
|
||||
sed -i s#/etc/apache2/ssl.crt/server-ca.crt#$SSLCertificateChainFile# $sslconf
|
||||
sed -i s/#SSLCertificateChainFile/SSLCertificateChainFile/ $sslconf
|
||||
# apply changes
|
||||
a2ensite default-ssl.conf
|
||||
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_hubzilla {
|
||||
print_info "installing hubzilla addons..."
|
||||
cd /var/www/html/
|
||||
util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons
|
||||
mkdir -p "store/[data]/smarty3"
|
||||
chmod -R 777 store
|
||||
touch .htconfig.php
|
||||
chmod ou+w .htconfig.php
|
||||
cd /var/www/
|
||||
chown -R www-data:www-data html
|
||||
chown root:www-data /var/www/html/
|
||||
chown root:www-data /var/www/html/.htaccess
|
||||
chmod 0644 /var/www/html/.htaccess
|
||||
# try to switch off email registration
|
||||
sed -i "s/verify_email.*1/verify_email'] = 0/" /var/www/html/view/*/ht*
|
||||
if [ -n "`grep -r 'verify_email.*1' /var/www/html/view/`" ]
|
||||
then
|
||||
print_warn "Hubzillas registration prozess might have email verification switched on."
|
||||
fi
|
||||
print_info "installed hubzilla"
|
||||
}
|
||||
|
||||
function rewrite_to_https {
|
||||
print_info "configuring apache to redirect http to httpS ..."
|
||||
htaccessfile=/var/www/html/.htaccess
|
||||
if grep -i "https" $htaccessfile
|
||||
then
|
||||
print_info "...configuring apache to redirect http to httpS was already done in $htaccessfile"
|
||||
else
|
||||
sed -i "s#QSA]#QSA]\\n RewriteCond %{SERVER_PORT} !^443$\\n RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]#" $htaccessfile
|
||||
fi
|
||||
service apache2 restart
|
||||
}
|
||||
|
||||
# This will allways overwrite both config files
|
||||
# - internal disk
|
||||
# - external disk (LUKS + ext4)
|
||||
# of rsnapshot for hubzilla
|
||||
function install_rsnapshot {
|
||||
print_info "installing rsnapshot..."
|
||||
nocheck_install "rsnapshot"
|
||||
# internal disk
|
||||
cp -f /etc/rsnapshot.conf $snapshotconfig
|
||||
sed -i "s/^cmd_cp/#cmd_cp/" $snapshotconfig
|
||||
sed -i "s/^backup/#backup/" $snapshotconfig
|
||||
echo "backup /var/lib/mysql/ localhost/" >> $snapshotconfig
|
||||
echo "backup /var/www/html/ localhost/" >> $snapshotconfig
|
||||
echo "backup /var/www/letsencrypt/ localhost/" >> $snapshotconfig
|
||||
# external disk
|
||||
if [ -n "$backup_device_name" ]
|
||||
then
|
||||
cp -f /etc/rsnapshot.conf $snapshotconfig_external_device
|
||||
sed -i "s#snapshot_root.*#snapshot_root $backup_mount_point#" $snapshotconfig_external_device
|
||||
sed -i "/alpha/s/6/30/" $snapshotconfig_external_device
|
||||
sed -i "s/^cmd_cp/#cmd_cp/" $snapshotconfig_external_device
|
||||
sed -i "s/^backup/#backup/" $snapshotconfig_external_device
|
||||
if [ -z "`grep 'letsencrypt' $snapshotconfig_external_device`" ]
|
||||
then
|
||||
echo "backup /var/lib/mysql/ localhost/" >> $snapshotconfig_external_device
|
||||
echo "backup /var/www/html/ localhost/" >> $snapshotconfig_external_device
|
||||
echo "backup /var/www/letsencrypt/ localhost/" >> $snapshotconfig_external_device
|
||||
fi
|
||||
else
|
||||
print_info "No backup configuration (rsnapshot) for external device configured. Reason: backup_device_name and/or backup_device_pass not given in $configfile"
|
||||
fi
|
||||
}
|
||||
|
||||
function install_cryptosetup {
|
||||
print_info "installing cryptsetup..."
|
||||
nocheck_install "cryptsetup"
|
||||
}
|
||||
|
||||
function configure_cron_daily {
|
||||
print_info "configuring cron..."
|
||||
# every 10 min for poller.php
|
||||
if [ -z "`grep 'poller.php' /etc/crontab`" ]
|
||||
then
|
||||
echo "*/10 * * * * www-data cd /var/www/html; php Zotlabs/Daemon/Master.php Cron >> /dev/null 2>&1" >> /etc/crontab
|
||||
fi
|
||||
# Run external script daily at 05:30
|
||||
# - stop apache and mysql-server
|
||||
# - backup hubzilla
|
||||
# - update hubzilla core and addon
|
||||
# - update and upgrade linux
|
||||
# - reboot
|
||||
echo "#!/bin/sh" > /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "echo \" \"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"+++ \$(date) +++\"" >> /var/www/$hubzilladaily
|
||||
echo "echo \" \"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$hubzilladaily
|
||||
echo "bash $le_dir/dehydrated --cron --config $le_dir/config.sh" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# stop hubzilla" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - stoping apache and mysql...\"" >> /var/www/$hubzilladaily
|
||||
echo "service apache2 stop" >> /var/www/$hubzilladaily
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistancies" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# backup" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - try to mount external device for backup...\"" >> /var/www/$hubzilladaily
|
||||
echo "backup_device_name=$backup_device_name" >> /var/www/$hubzilladaily
|
||||
echo "backup_device_pass=$backup_device_pass" >> /var/www/$hubzilladaily
|
||||
echo "backup_mount_point=$backup_mount_point" >> /var/www/$hubzilladaily
|
||||
echo "device_mounted=0" >> /var/www/$hubzilladaily
|
||||
echo "if [ -n \"$backup_device_name\" ]" >> /var/www/$hubzilladaily
|
||||
echo "then" >> /var/www/$hubzilladaily
|
||||
echo " if blkid | grep $backup_device_name" >> /var/www/$hubzilladaily
|
||||
echo " then" >> /var/www/$hubzilladaily
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " echo \"decrypting backup device...\"" >> /var/www/$hubzilladaily
|
||||
echo " echo "\"$backup_device_pass\"" | cryptsetup luksOpen $backup_device_name cryptobackup" >> /var/www/$hubzilladaily
|
||||
fi
|
||||
echo " if [ ! -d $backup_mount_point ]" >> /var/www/$hubzilladaily
|
||||
echo " then" >> /var/www/$hubzilladaily
|
||||
echo " mkdir $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
echo " fi" >> /var/www/$hubzilladaily
|
||||
echo " echo \"mounting backup device...\"" >> /var/www/$hubzilladaily
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " if mount /dev/mapper/cryptobackup $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
else
|
||||
echo " if mount $backup_device_name $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
fi
|
||||
echo " then" >> /var/www/$hubzilladaily
|
||||
echo " device_mounted=1" >> /var/www/$hubzilladaily
|
||||
echo " echo \"device $backup_device_name is now mounted. Starting backup...\"" >> /var/www/$hubzilladaily
|
||||
echo " rsnapshot -c $snapshotconfig_external_device alpha" >> /var/www/$hubzilladaily
|
||||
echo " echo \"\$(date) - disk sizes...\"" >> /var/www/$hubzilladaily
|
||||
echo " df -h" >> /var/www/$hubzilladaily
|
||||
echo " echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily
|
||||
echo " du -h $backup_mount_point | grep mysql/hubzilla" >> /var/www/$hubzilladaily
|
||||
echo " echo \"unmounting backup device...\"" >> /var/www/$hubzilladaily
|
||||
echo " umount $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
echo " else" >> /var/www/$hubzilladaily
|
||||
echo " echo \"failed to mount device $backup_device_name\"" >> /var/www/$hubzilladaily
|
||||
echo " fi" >> /var/www/$hubzilladaily
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " echo \"closing decrypted backup device...\"" >> /var/www/$hubzilladaily
|
||||
echo " cryptsetup luksClose cryptobackup" >> /var/www/$hubzilladaily
|
||||
fi
|
||||
echo " fi" >> /var/www/$hubzilladaily
|
||||
echo "fi" >> /var/www/$hubzilladaily
|
||||
echo "if [ \$device_mounted == 0 ]" >> /var/www/$hubzilladaily
|
||||
echo "then" >> /var/www/$hubzilladaily
|
||||
echo " echo \"device could not be mounted $backup_device_name. No backup written.\"" >> /var/www/$hubzilladaily
|
||||
echo "fi" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily
|
||||
echo "du -h /var/lib/mysql/ | grep mysql/hubzilla" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# update" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating dehydrated...\"" >> /var/www/$hubzilladaily
|
||||
echo "git -C /var/www/letsencrypt/ pull" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating hubhilla core...\"" >> /var/www/$hubzilladaily
|
||||
echo "(cd /var/www/html/ ; util/udall)" >> /var/www/$hubzilladaily
|
||||
echo "chown -R www-data:www-data /var/www/html/ # make all accessable for the webserver" >> /var/www/$hubzilladaily
|
||||
echo "chown root:www-data /var/www/html/.htaccess" >> /var/www/$hubzilladaily
|
||||
echo "chmod 0644 /var/www/html/.htaccess # www-data can read but not write it" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating linux...\"" >> /var/www/$hubzilladaily
|
||||
echo "apt-get -q -y update && apt-get -q -y dist-upgrade && apt-get -q -y autoremove # update linux and upgrade" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - Backup hubzilla and update linux finished. Rebooting...\"" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "reboot" >> /var/www/$hubzilladaily
|
||||
|
||||
if [ -z "`grep 'hubzilla-daily.sh' /etc/crontab`" ]
|
||||
then
|
||||
echo "30 05 * * * root /bin/bash /var/www/$hubzilladaily >> /var/www/html/hubzilla-daily.log 2>&1" >> /etc/crontab
|
||||
echo "0 0 1 * * root rm /var/www/html/hubzilla-daily.log" >> /etc/crontab
|
||||
fi
|
||||
|
||||
# This is active after either "reboot" or "/etc/init.d/cron reload"
|
||||
print_info "configured cron for updates/upgrades"
|
||||
}
|
||||
|
||||
function write_uninstall_script {
|
||||
print_info "writing uninstall script..."
|
||||
|
||||
cat > /var/www/hubzilla-remove.sh <<END
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script removes Hubzilla.
|
||||
# You might do this for a fresh start using the script.
|
||||
# The script will remove (almost everything) what was installed by the script,
|
||||
# all applications including hubzilla and its database.
|
||||
#
|
||||
# Backup the certificates of letsencrypt (you never know)
|
||||
cp -a /var/www/letsencrypt/ ~/backup_le_certificats
|
||||
#
|
||||
# Removal
|
||||
apt-get remove apache2 apache2-utils libapache2-mod-php5 php5 php-pear php5-xcache php5-curl php5-mcrypt php5-gd php5-mysql mysql-server mysql-client phpmyadmin
|
||||
apt-get purge apache2 apache2-utils libapache2-mod-php5 php5 php-pear php5-xcache php5-curl php5-mcrypt php5-gd php5-mysql mysql-server mysql-client phpmyadmin
|
||||
apt-get autoremove
|
||||
apt-get clean
|
||||
rm /etc/rsnapshot_hubzilla.conf
|
||||
rm /etc/rsnapshot_hubzilla_external_device.conf
|
||||
rm -R /etc/apache2/
|
||||
rm -R /var/lib/mysql/
|
||||
rm -R /var/www
|
||||
rm -R /etc/selfhost/
|
||||
# uncomment the next line if you want to remove the backups
|
||||
# rm -R /var/cache/rsnapshot
|
||||
nano /etc/crontab # remove entries there manually
|
||||
END
|
||||
chmod -x /var/www/hubzilla-remove.sh
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# START OF PROGRAM
|
||||
########################################################################
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
||||
|
||||
check_sanity
|
||||
|
||||
# Read config file edited by user
|
||||
configfile=hubzilla-config.txt
|
||||
source $configfile
|
||||
|
||||
selfhostdir=/etc/selfhost
|
||||
selfhostscript=selfhost-updater.sh
|
||||
hubzilladaily=hubzilla-daily.sh
|
||||
plugins_update=.homeinstall/plugins_update.sh
|
||||
snapshotconfig=/etc/rsnapshot_hubzilla.conf
|
||||
snapshotconfig_external_device=/etc/rsnapshot_hubzilla_external_device.conf
|
||||
backup_mount_point=/media/hubzilla_backup
|
||||
le_dir=/var/www/letsencrypt
|
||||
sslconf=/etc/apache2/sites-available/default-ssl.conf
|
||||
|
||||
#set -x # activate debugging from here
|
||||
|
||||
check_config
|
||||
stop_hubzilla
|
||||
update_upgrade
|
||||
install_curl
|
||||
install_sendmail
|
||||
install_apache
|
||||
install_imagemagick
|
||||
install_php
|
||||
install_mysql
|
||||
install_phpmyadmin
|
||||
create_hubzilla_db
|
||||
run_freedns
|
||||
install_run_selfhost
|
||||
ping_domain
|
||||
configure_cron_freedns
|
||||
configure_cron_selfhost
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_letsencrypt
|
||||
configure_apache_for_https
|
||||
check_https
|
||||
else
|
||||
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
|
||||
fi
|
||||
|
||||
install_hubzilla
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
rewrite_to_https
|
||||
install_rsnapshot
|
||||
else
|
||||
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
|
||||
fi
|
||||
|
||||
configure_cron_daily
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_cryptosetup
|
||||
write_uninstall_script
|
||||
else
|
||||
print_info "is localhost - skipped installation of cryptosetup"
|
||||
fi
|
||||
|
||||
#set +x # stop debugging from here
|
||||
|
||||
144
.homeinstall/nginx-zotserver.conf.template
Normal file
144
.homeinstall/nginx-zotserver.conf.template
Normal file
@@ -0,0 +1,144 @@
|
||||
##
|
||||
# Hubzilla/Zap/Mistpark/Osada Nginx block configuration template
|
||||
# based on the example created by Olaf Conradi
|
||||
#
|
||||
# The files generated with this template will be added to
|
||||
# /etc/nginx/sites-available & /etc/nginx/sites-enabled (symlink)
|
||||
##
|
||||
|
||||
##
|
||||
# You should look at the following URL's in order to grasp a solid understanding
|
||||
# of Nginx configuration files in order to fully unleash the power of Nginx.
|
||||
#
|
||||
# http://wiki.nginx.org/Pitfalls
|
||||
# http://wiki.nginx.org/QuickStart
|
||||
# http://wiki.nginx.org/Configuration
|
||||
##
|
||||
|
||||
##
|
||||
# This configuration assumes
|
||||
# You filled the zotserver-config.txt file
|
||||
# Your domain/subdomain is functionnal
|
||||
# You want all traffic to be https
|
||||
# You have PHP FastCGI Process Manager (php-fpm) running on localhost
|
||||
##
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name SERVER_NAME;
|
||||
|
||||
# HTTP > HTTPS #
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
##
|
||||
# Configure Red with SSL
|
||||
#
|
||||
# All requests are routed to the front controller
|
||||
# except for certain known file types like images, css, etc.
|
||||
# Those are served statically whenever possible with a
|
||||
# fall back to the front controller (needed for avatars, for example)
|
||||
##
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name SERVER_NAME;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/letsencrypt/live/SERVER_NAME/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/SERVER_NAME/privkey.pem;
|
||||
ssl_session_timeout 5m;
|
||||
# DO WE NEED TO REVIEW THE FOLLOWING SETTINGS?
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
fastcgi_param HTTPS on;
|
||||
|
||||
charset utf-8;
|
||||
root INSTALL_PATH;
|
||||
index index.php;
|
||||
access_log /var/log/nginx/ZOTSERVER_LOG;
|
||||
|
||||
#Uncomment the following line to include a standard configuration file
|
||||
#Note that the most specific rule wins and your standard configuration
|
||||
#will therefore *add* to this file, but not override it.
|
||||
#include standard.conf
|
||||
|
||||
# allow uploads up to 20MB in size
|
||||
client_max_body_size 20m;
|
||||
client_body_buffer_size 128k;
|
||||
|
||||
include mime.types;
|
||||
|
||||
# rewrite to front controller as default rule
|
||||
location / {
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?req=$1;
|
||||
}
|
||||
}
|
||||
|
||||
# make sure webfinger and other well known services aren't blocked
|
||||
# by denying dot files and rewrite request to the front controller
|
||||
location ^~ /.well-known/ {
|
||||
allow all;
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?req=$1;
|
||||
}
|
||||
}
|
||||
|
||||
# statically serve these file types when possible
|
||||
# otherwise fall back to front controller
|
||||
# allow browser to cache them
|
||||
# added .htm for advanced source code editor library
|
||||
# location ~* \.(jpg|jpeg|gif|png|ico|css|js|htm|html|map|ttf|woff|woff2|svg)$ {
|
||||
# expires 30d;
|
||||
# try_files $uri /index.php?req=$uri&$args;
|
||||
# }
|
||||
# SHOULD WE UNCOMMENT THE ABOVE LINES ?
|
||||
|
||||
# block these file types
|
||||
location ~* \.(tpl|md|tgz|log|out)$ {
|
||||
deny all;
|
||||
}
|
||||
|
||||
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
|
||||
# or a unix socket
|
||||
location ~* \.php$ {
|
||||
# IS THE FOLLOWING STILL RELEVANT AS OF AUGUST 2020?
|
||||
# Zero-day exploit defense.
|
||||
# http://forum.nginx.org/read.php?2,88845,page=3
|
||||
# Won't work properly (404 error) if the file is not stored on this
|
||||
# server, which is entirely possible with php-fpm/php-fcgi.
|
||||
# Comment the 'try_files' line out if you set up php-fpm/php-fcgi on
|
||||
# another machine. And then cross your fingers that you won't get hacked.
|
||||
try_files $uri =404;
|
||||
|
||||
# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
|
||||
# With php5-cgi alone:
|
||||
# fastcgi_pass 127.0.0.1:9000;
|
||||
|
||||
# With php-fpm:
|
||||
fastcgi_pass unix:PHP_FPM_SOCK;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
}
|
||||
|
||||
# deny access to all dot files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
|
||||
#deny access to store
|
||||
|
||||
location ~ /store {
|
||||
deny all;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,35 +2,50 @@
|
||||
### 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
|
||||
# Example: db_pass="this password has blanks in it"
|
||||
db_pass=
|
||||
|
||||
###############################################
|
||||
### MANDATORY - let's encrypt #################
|
||||
#
|
||||
# Hubilla requires encrypted communication via secure HTTP (HTTPS).
|
||||
# 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
|
||||
# Please give the domain name of your hub/instance
|
||||
#
|
||||
# Example: my.cooldomain.org
|
||||
# Example: cooldomain.org
|
||||
#
|
||||
# Example: localhost (test installation without certificates for httpS)
|
||||
# You might use "localhost" for a LOCAL TEST installation.
|
||||
# This is usefull if you want to debug the server inside a VM.
|
||||
#
|
||||
# Email is optional
|
||||
# Example: localhost
|
||||
#
|
||||
# Email is optional if you use "localhost".
|
||||
#
|
||||
#
|
||||
le_domain=
|
||||
le_email=
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - Webserver choice ###############
|
||||
#
|
||||
# Please indicate if you want to choose Nginx
|
||||
# or Apache as your web server
|
||||
#
|
||||
# Valid strings are nginx or apache (lower case),
|
||||
# any other will stop the setup script.
|
||||
#
|
||||
webserver=apache
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - selfHOST - dynamic IP address ##
|
||||
#
|
||||
# 1. Register a domain at selfhost.de
|
||||
# - choose offer "DOMAIN dynamisch" 1,50€/mon at 08.01.2016
|
||||
# - 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"
|
||||
@@ -84,7 +99,7 @@ freedns_key=
|
||||
# - encrypted LUKS + ext4, or
|
||||
# - ext4
|
||||
#
|
||||
# You should test to mount the device befor you run the script
|
||||
# You should test to mount the device before you run the script
|
||||
# (hubzilla-setup.sh).
|
||||
# How to find your (pluged-in) devices?
|
||||
#
|
||||
@@ -141,10 +156,13 @@ backup_device_pass=
|
||||
#
|
||||
###############################################
|
||||
#
|
||||
# Database for hubzilla
|
||||
hubzilla_db_name=hubzilla
|
||||
hubzilla_db_user=hubzilla
|
||||
hubzilla_db_pass=$db_pass
|
||||
# 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
|
||||
793
.homeinstall/zotserver-setup.sh
Executable file
793
.homeinstall/zotserver-setup.sh
Executable file
@@ -0,0 +1,793 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# How to use
|
||||
# ----------
|
||||
#
|
||||
# This file automates the installation of
|
||||
# - hubzilla: https://zotlabs.org/page/hubzilla/hubzilla-project and
|
||||
# - zap: https://zotlabs.com/zap/
|
||||
# - misty : https://zotlabs.com/misty/
|
||||
# - osada : https://codeberg.org/zot/osada
|
||||
# - redmatrix : https://codeberg.org/zot/redmatrix
|
||||
# under Debian Linux "Buster"
|
||||
#
|
||||
# 1) Copy the file "zotserver-config.txt.template" to "zotserver-config.txt"
|
||||
# Follow the instuctions there
|
||||
#
|
||||
# 2) Switch to user "root" by typing "su -"
|
||||
#
|
||||
# 3) Run with "./zotserver-setup.sh"
|
||||
# If this fails check if you can execute the script.
|
||||
# - To make it executable type "chmod +x zotserver-setup.sh"
|
||||
# - or run "bash zotserver-setup.sh"
|
||||
#
|
||||
#
|
||||
# What does this script do basically?
|
||||
# -----------------------------------
|
||||
#
|
||||
# This file automates the installation of a Zot hub/instance under Debian Linux
|
||||
# - install
|
||||
# * apache webserver,
|
||||
# * php,
|
||||
# * mariadb - the database for zotserver,
|
||||
# * adminer,
|
||||
# * git to download and update addons
|
||||
# - configure cron
|
||||
# * "Run.php" for regular background processes of your Zot hub/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
|
||||
# * backup your server's database and files (rsync)
|
||||
# - run letsencrypt to create, register and use a certifacte for https
|
||||
#
|
||||
#
|
||||
# Discussion
|
||||
# ----------
|
||||
#
|
||||
# Security - password is the same for mysql-server, phpmyadmin and your hub/instance db
|
||||
# - The script runs into installation errors for phpmyadmin if it uses
|
||||
# different passwords. For the sake of simplicity one single password.
|
||||
#
|
||||
# How to restore from backup
|
||||
# --------------------------
|
||||
#
|
||||
# (Some explanations here would certainly be useful)
|
||||
#
|
||||
# Daily backup
|
||||
# ------------
|
||||
#
|
||||
# The installation
|
||||
# - writes a shell script in /var/www/
|
||||
# - creates a daily cron that runs this script
|
||||
#
|
||||
# The script makes a (daily) backup of all relevant files
|
||||
# - /var/lib/mysql/ > database
|
||||
# - /var/www/ > hubzilla/zap/misty from git repository
|
||||
# - /etc/letsencrypt/ > certificates
|
||||
#
|
||||
# The backup will be written on an external disk compatible to LUKS+ext4 (see zotserver-config.txt)
|
||||
#
|
||||
# How to restore from backup
|
||||
# --------------------------
|
||||
#
|
||||
# (Some explanations here would certainly be useful)
|
||||
#
|
||||
#
|
||||
# Credits
|
||||
# -------
|
||||
#
|
||||
# The script is based on Thomas Willinghams script "debian-setup.sh"
|
||||
# which he used to install the red#matrix.
|
||||
#
|
||||
# The documentation for bash is here
|
||||
# https://www.gnu.org/software/bash/manual/bash.html
|
||||
#
|
||||
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 10' /etc/issue
|
||||
then
|
||||
die "Linux 10 (buster) 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
|
||||
# backup is important and should be checked
|
||||
if [ -n "$backup_device_name" ]
|
||||
then
|
||||
if [ ! -d "$backup_mount_point" ]
|
||||
then
|
||||
mkdir "$backup_mount_point"
|
||||
fi
|
||||
device_mounted=0
|
||||
if fdisk -l | grep -i "$backup_device_name.*linux"
|
||||
then
|
||||
print_info "ok - filesystem of external device is linux"
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo "$backup_device_pass" | cryptsetup luksOpen $backup_device_name cryptobackup
|
||||
if mount /dev/mapper/cryptobackup /media/zotserver_backup
|
||||
then
|
||||
device_mounted=1
|
||||
print_info "ok - could encrypt and mount external backup device"
|
||||
umount /media/zotserver_backup
|
||||
else
|
||||
print_warn "backup to external device will fail because encryption failed"
|
||||
fi
|
||||
cryptsetup luksClose cryptobackup
|
||||
else
|
||||
if mount $backup_device_name /media/zotserver_backup
|
||||
then
|
||||
device_mounted=1
|
||||
print_info "ok - could mount external backup device"
|
||||
umount /media/zotserver_backup
|
||||
else
|
||||
print_warn "backup to external device will fail because mount failed"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
print_warn "backup to external device will fail because filesystem is either not linux or 'backup_device_name' is not correct in $configfile"
|
||||
fi
|
||||
if [ $device_mounted == 0 ]
|
||||
then
|
||||
die "backup device not ready"
|
||||
fi
|
||||
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
|
||||
print_info "updated and upgraded linux"
|
||||
}
|
||||
|
||||
function check_install {
|
||||
if [ -z "`which "$1" 2>/dev/null`" ]
|
||||
then
|
||||
# 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 -q -y install $2
|
||||
print_info "installed $2 installed for $1"
|
||||
else
|
||||
print_warn "$2 already installed"
|
||||
fi
|
||||
}
|
||||
|
||||
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 {
|
||||
if [ $webserver = "nginx" ]
|
||||
then
|
||||
print_info "stopping nginx webserver..."
|
||||
systemctl stop nginx
|
||||
elif [ $webserver = "apache" ]
|
||||
then
|
||||
print_info "stopping apache webserver..."
|
||||
systemctl stop apache2
|
||||
fi
|
||||
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_nginx {
|
||||
print_info "installing nginx..."
|
||||
nocheck_install "nginx"
|
||||
systemctl restart nginx
|
||||
}
|
||||
|
||||
function add_vhost {
|
||||
print_info "adding apache vhost"
|
||||
echo "<VirtualHost *:80>" >> "/etc/apache2/sites-available/${le_domain}.conf"
|
||||
echo "ServerName ${le_domain}" >> "/etc/apache2/sites-available/${le_domain}.conf"
|
||||
echo "DocumentRoot $install_path" >> "/etc/apache2/sites-available/${le_domain}.conf"
|
||||
echo "</VirtualHost>" >> "/etc/apache2/sites-available/${le_domain}.conf"
|
||||
a2ensite $le_domain
|
||||
}
|
||||
|
||||
function add_nginx_block {
|
||||
print_info "adding nginx block"
|
||||
sed "s|SERVER_NAME|${le_domain}|g;s|INSTALL_PATH|${install_path}|g;s|ZOTSERVER_LOG|${install_folder}-${zotserver}.log|;s|PHP_FPM_SOCK|$(ls /var/run/php/*sock)|;" nginx-zotserver.conf.template >> /etc/nginx/sites-enabled/${le_domain}.conf
|
||||
ln -s /etc/nginx/sites-enabled/${le_domain}.conf /etc/nginx/sites-available/
|
||||
}
|
||||
|
||||
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..."
|
||||
if [ $webserver = "nginx" ]
|
||||
then
|
||||
nocheck_install "php php-pear php-curl php-gd php-mbstring php-xml php-zip php-fpm"
|
||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/fpm/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/fpm/php.ini
|
||||
systemctl reload php7.3-fpm
|
||||
elif [ $webserver = "apache" ]
|
||||
then
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip"
|
||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/apache2/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini
|
||||
fi
|
||||
}
|
||||
|
||||
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 "$zotserver_db_name" ]
|
||||
then
|
||||
zotserver_db_name=$zotserver
|
||||
fi
|
||||
if [ -z "$zotserver_db_user" ]
|
||||
then
|
||||
zotserver_db_user=$zotserver
|
||||
fi
|
||||
if [ -z "$zotserver_db_pass" ]
|
||||
then
|
||||
die "zotserver_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 $zotserver_db_name) ]
|
||||
then
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $zotserver_db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $zotserver_db_user@localhost IDENTIFIED BY '$zotserver_db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $zotserver_db_name.* to $zotserver_db_user@localhost identified by '$zotserver_db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$mysqlpass -e "$SQL"
|
||||
else
|
||||
die "Can't write over an already existing database!"
|
||||
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
|
||||
if [ $webserver = "nginx" ]
|
||||
then
|
||||
nocheck_install "certbot"
|
||||
print_info "run certbot..."
|
||||
systemctl stop nginx
|
||||
certbot certonly --standalone -d $le_domain -m $le_email --agree-tos --non-interactive
|
||||
systemctl start nginx
|
||||
elif [ $webserver = "apache" ]
|
||||
then
|
||||
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
|
||||
fi
|
||||
}
|
||||
|
||||
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 zotserver_name {
|
||||
if git remote -v | grep -i "origin.*hubzilla.*"
|
||||
then
|
||||
zotserver=hubzilla
|
||||
elif git remote -v | grep -i "origin.*zap.*"
|
||||
then
|
||||
zotserver=zap
|
||||
elif git remote -v | grep -i "origin.*misty.*"
|
||||
then
|
||||
zotserver=misty
|
||||
elif git remote -v | grep -i "origin.*osada.*"
|
||||
then
|
||||
zotserver=osada
|
||||
elif git remote -v | grep -i "origin.*redmatrix.*"
|
||||
then
|
||||
zotserver=redmatrix
|
||||
else
|
||||
die "neither redmatrix, osada, misty, zap nor hubzilla repository > did not install redmatrix/osada/misty/zap/hubzilla"
|
||||
fi
|
||||
}
|
||||
|
||||
function install_zotserver {
|
||||
print_info "installing addons..."
|
||||
cd $install_path/
|
||||
if [ $zotserver = "hubzilla" ]
|
||||
then
|
||||
print_info "hubzilla"
|
||||
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
|
||||
elif [ $zotserver = "zap" ]
|
||||
then
|
||||
print_info "zap"
|
||||
util/add_addon_repo https://codeberg.org/zot/zap-addons.git zaddons
|
||||
elif [ $zotserver = "misty" ]
|
||||
then
|
||||
print_info "misty"
|
||||
util/add_addon_repo https://codeberg.org/zot/misty-addons.git maddons
|
||||
elif [ $zotserver = "osada" ]
|
||||
then
|
||||
print_info "osada"
|
||||
util/add_addon_repo https://codeberg.org/zot/osada-addons.git oaddons
|
||||
elif [ $zotserver = "redmatrix" ]
|
||||
then
|
||||
print_info "redmatrix"
|
||||
util/add_addon_repo https://codeberg.org/zot/redmatrix-addons.git raddons
|
||||
else
|
||||
die "neither redmatrix, osada, misty, zap nor hubzilla repository > did not install addons or redmatrix/osada/misty/zap/hubzilla"
|
||||
fi
|
||||
mkdir -p "cache/smarty3"
|
||||
mkdir -p "store"
|
||||
chmod -R 777 store
|
||||
touch .htconfig.php
|
||||
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 install_rsync {
|
||||
print_info "installing rsync..."
|
||||
nocheck_install "rsync"
|
||||
}
|
||||
|
||||
function install_cryptosetup {
|
||||
print_info "installing cryptsetup..."
|
||||
nocheck_install "cryptsetup"
|
||||
}
|
||||
|
||||
function configure_zotserverdaily {
|
||||
echo "#!/bin/sh" >> /var/www/$zotserverdaily
|
||||
echo "#" >> /var/www/$zotserverdaily
|
||||
echo "# update of $le_domain Zot hub/instance" >> /var/www/$zotserverdaily
|
||||
echo "echo \"\$(date) - updating core and addons...\"" >> /var/www/$zotserverdaily
|
||||
echo "echo \"reaching git repository for $le_domain $zotserver hub/instance...\"" >> /var/www/$zotserverdaily
|
||||
echo "(cd $install_path ; util/udall)" >> /var/www/$zotserverdaily
|
||||
echo "chown -R www-data:www-data $install_path # make all accessible for the webserver" >> /var/www/$zotserverdaily
|
||||
if [ $webserver = "apache" ]
|
||||
then
|
||||
echo "chown root:www-data $install_path/.htaccess" >> /var/www/$zotserverdaily
|
||||
echo "chmod 0644 $install_path/.htaccess # www-data can read but not write it" >> /var/www/$zotserverdaily
|
||||
fi
|
||||
chmod a+x /var/www/$zotserverdaily
|
||||
}
|
||||
|
||||
function configure_cron_daily {
|
||||
print_info "configuring cron..."
|
||||
# every 10 min for poller.php
|
||||
if [ -z "`grep '$install_path.*Run.php' /etc/crontab`" ]
|
||||
then
|
||||
echo "*/10 * * * * www-data cd $install_path; php Zotlabs/Daemon/Run.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
|
||||
# - backup db, files ($install_path), certificates if letsencrypt
|
||||
# - update zotserver 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/$zotcron
|
||||
echo "#" >> /var/www/$zotcron
|
||||
echo "echo \" \"" >> /var/www/$zotcron
|
||||
echo "echo \"+++ \$(date) +++\"" >> /var/www/$zotcron
|
||||
echo "echo \" \"" >> /var/www/$zotcron
|
||||
echo "echo \"\$(date) - stopping $webserver and mysql...\"" >> /var/www/$zotcron
|
||||
if [ $webserver = "nginx" ]
|
||||
then
|
||||
echo "systemctl stop nginx" >> /var/www/$zotcron
|
||||
elif [ $webserver = "apache" ]
|
||||
then
|
||||
echo "service apache2 stop" >> /var/www/$zotcron
|
||||
fi
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /var/www/$zotcron
|
||||
echo "#" >> /var/www/$zotcron
|
||||
echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$zotcron
|
||||
echo "certbot renew --noninteractive" >> /var/www/$zotcron
|
||||
echo "#" >> /var/www/$zotcron
|
||||
echo "# backup" >> /var/www/$zotcron
|
||||
echo "echo \"\$(date) - try to mount external device for backup...\"" >> /var/www/$zotcron
|
||||
echo "backup_device_name=$backup_device_name" >> /var/www/$zotcron
|
||||
echo "backup_device_pass=$backup_device_pass" >> /var/www/$zotcron
|
||||
echo "backup_mount_point=$backup_mount_point" >> /var/www/$zotcron
|
||||
echo "device_mounted=0" >> /var/www/$zotcron
|
||||
echo "if [ -n \"\$backup_device_name\" ]" >> /var/www/$zotcron
|
||||
echo "then" >> /var/www/$zotcron
|
||||
echo " if blkid | grep $backup_device_name" >> /var/www/$zotcron
|
||||
echo " then" >> /var/www/$zotcron
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " echo \"decrypting backup device...\"" >> /var/www/$zotcron
|
||||
echo " echo "\"$backup_device_pass\"" | cryptsetup luksOpen $backup_device_name cryptobackup" >> /var/www/$zotcron
|
||||
fi
|
||||
echo " if [ ! -d $backup_mount_point ]" >> /var/www/$zotcron
|
||||
echo " then" >> /var/www/$zotcron
|
||||
echo " mkdir $backup_mount_point" >> /var/www/$zotcron
|
||||
echo " fi" >> /var/www/$zotcron
|
||||
echo " echo \"mounting backup device...\"" >> /var/www/$zotcron
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " if mount /dev/mapper/cryptobackup $backup_mount_point" >> /var/www/$zotcron
|
||||
else
|
||||
echo " if mount $backup_device_name $backup_mount_point" >> /var/www/$zotcron
|
||||
fi
|
||||
echo " then" >> /var/www/$zotcron
|
||||
echo " device_mounted=1" >> /var/www/$zotcron
|
||||
echo " echo \"device $backup_device_name is now mounted. Starting backup...\"" >> /var/www/$zotcron
|
||||
echo " rsync -a --delete /var/lib/mysql/ /media/zotserver_backup/mysql" >> /var/www/$zotcron
|
||||
echo " rsync -a --delete /var/www/ /media/zotserver_backup/www" >> /var/www/$zotcron
|
||||
echo " rsync -a --delete /etc/letsencrypt/ /media/zotserver_backup/letsencrypt" >> /var/www/$zotcron
|
||||
echo " echo \"\$(date) - disk sizes...\"" >> /var/www/$zotcron
|
||||
echo " df -h" >> /var/www/$zotcron
|
||||
echo " echo \"\$(date) - db size...\"" >> /var/www/$zotcron
|
||||
echo " du -h $backup_mount_point | grep mysql/zotserver" >> /var/www/$zotcron
|
||||
echo " echo \"unmounting backup device...\"" >> /var/www/$zotcron
|
||||
echo " umount $backup_mount_point" >> /var/www/$zotcron
|
||||
echo " else" >> /var/www/$zotcron
|
||||
echo " echo \"failed to mount device $backup_device_name\"" >> /var/www/$zotcron
|
||||
echo " fi" >> /var/www/$zotcron
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " echo \"closing decrypted backup device...\"" >> /var/www/$zotcron
|
||||
echo " cryptsetup luksClose cryptobackup" >> /var/www/$zotcron
|
||||
fi
|
||||
echo " fi" >> /var/www/$zotcron
|
||||
echo "fi" >> /var/www/$zotcron
|
||||
echo "if [ \$device_mounted == 0 ]" >> /var/www/$zotcron
|
||||
echo "then" >> /var/www/$zotcron
|
||||
echo " echo \"device could not be mounted $backup_device_name. No backup written.\"" >> /var/www/$zotcron
|
||||
echo "fi" >> /var/www/$zotcron
|
||||
echo "#" >> /var/www/$zotcron
|
||||
echo "echo \"\$(date) - db size...\"" >> /var/www/$zotcron
|
||||
echo "du -h /var/lib/mysql/ | grep mysql/" >> /var/www/$zotcron
|
||||
echo "#" >> /var/www/$zotcron
|
||||
echo "cd /var/www" >> /var/www/$zotcron
|
||||
echo "for f in *-daily.sh; do \"./\${f}\"; done" >> /var/www/$zotcron
|
||||
echo "echo \"\$(date) - updating linux...\"" >> /var/www/$zotcron
|
||||
echo "apt-get -q -y update && apt-get -q -y dist-upgrade && apt-get -q -y autoremove # update linux and upgrade" >> /var/www/$zotcron
|
||||
echo "echo \"\$(date) - Backup and update finished. Rebooting...\"" >> /var/www/$zotcron
|
||||
echo "#" >> /var/www/$zotcron
|
||||
echo "shutdown -r now" >> /var/www/$zotcron
|
||||
|
||||
# If global cron job does not exist we add it to /etc/crontab
|
||||
if grep -q $zotcron /etc/crontab
|
||||
then
|
||||
echo "cron job already in /etc/crontab"
|
||||
else
|
||||
echo "30 05 * * * root /bin/bash /var/www/$zotcron >> /var/www/zot-daily.log 2>&1" >> /etc/crontab
|
||||
echo "0 0 1 * * root rm /var/www/zot-daily.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
|
||||
|
||||
zotserver_name
|
||||
print_info "We're installing a $zotserver instance"
|
||||
install_path="$(dirname "$(pwd)")"
|
||||
install_folder="$(basename $install_path)"
|
||||
|
||||
# Read config file edited by user
|
||||
configfile=zotserver-config.txt
|
||||
source $configfile
|
||||
|
||||
selfhostdir=/etc/selfhost
|
||||
selfhostscript=selfhost-updater.sh
|
||||
zotcron="zotcron.sh"
|
||||
zotserverdaily="${install_folder}-${zotserver}-daily.sh"
|
||||
backup_mount_point="/media/zotserver_backup"
|
||||
|
||||
#set -x # activate debugging from here
|
||||
|
||||
check_config
|
||||
stop_zotserver
|
||||
update_upgrade
|
||||
install_curl
|
||||
install_wget
|
||||
install_sendmail
|
||||
if [ $webserver = "nginx" ]
|
||||
then
|
||||
install_nginx
|
||||
elif [ $webserver = "apache" ]
|
||||
then
|
||||
install_apache
|
||||
else
|
||||
die "Failed to install a Web server: 'webserver' not set to \"apache\" or \"nginx\" in $configfile"
|
||||
fi
|
||||
install_imagemagick
|
||||
install_php
|
||||
if [ $webserver = "nginx" ]
|
||||
then
|
||||
add_nginx_block
|
||||
elif [ $webserver = "apache" ]
|
||||
then
|
||||
if [ "$install_path" != "/var/www/html" ]
|
||||
then
|
||||
add_vhost
|
||||
fi
|
||||
fi
|
||||
install_mysql
|
||||
if [ $webserver = "apache" ]
|
||||
then
|
||||
install_adminer
|
||||
fi
|
||||
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_zotserverdaily
|
||||
|
||||
configure_cron_daily
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_cryptosetup
|
||||
install_rsync
|
||||
else
|
||||
print_info "is localhost - skipped installation of cryptosetup"
|
||||
fi
|
||||
|
||||
|
||||
#set +x # stop debugging from here
|
||||
535
CHANGELOG
535
CHANGELOG
@@ -1,3 +1,436 @@
|
||||
Hubzilla 5.0.6 (2020-12-17)
|
||||
- Fix zot hublocs with empty hubloc_id_url in DB caused by clone import bug
|
||||
- Only look for zot6 and zot hublocs in mod owa
|
||||
- Fix abconfig issue when cloning a channel
|
||||
- Call notifier with refresh_all instead of location when importing a clone
|
||||
- Use Libzot::encode_locations() instead of zot_encode_locations() in notifier
|
||||
- Fix missing zot hubloc hubloc_id_url when importing a clone
|
||||
- Implement Libzot::zot_record_preferred() in various places to prevent hubloc confusion
|
||||
|
||||
Addons
|
||||
- Fix wrong redirect path for check_form_security_token_redirectOnErr() in various addons
|
||||
|
||||
|
||||
Hubzilla 5.0.5 (2020-12-12)
|
||||
- Fix hubloc issue in mod getfile
|
||||
- Remove duplicate SQL query
|
||||
|
||||
|
||||
Hubzilla 5.0.4 (2020-12-01)
|
||||
- Fix regression updating the primary
|
||||
- Dismiss title in response activities
|
||||
|
||||
|
||||
Hubzilla 5.0.3 (2020-11-26)
|
||||
- Upgrade phpunit to version 9
|
||||
- Remove dbunit because its not maintained anymore
|
||||
- Add uuid version 5 based uuid's to imported feeds
|
||||
- Fix potential delivery loop
|
||||
- Fix actor of fetched activities not stored
|
||||
- Improve update mechanism for comments and likes to prevent page jumps
|
||||
- Fix issue where channel suggestions was suggesting oneself
|
||||
- Do not auto-update except for own actions
|
||||
- Introduce ctrl-enter shortcut to send comments and posts
|
||||
|
||||
Addons
|
||||
Pubcrawl: improve addressing of mentioned actors
|
||||
|
||||
|
||||
Hubzilla 5.0.2 (2020-11-16)
|
||||
- Fix edge case in acl selector
|
||||
- Fix ping_site()
|
||||
- Fix directory post url
|
||||
- Update russian translation
|
||||
- Implement polling for notifications (default) - SSE can be enabled in /admin/site if desired
|
||||
- DB update to remove hublocs with no hubloc_hash or no hubloc_callback
|
||||
- Do not save actors without an inbox
|
||||
- Fix import_hublocs()
|
||||
|
||||
Addons
|
||||
- Pubcrawl: do not save actors without an inbox
|
||||
- Diaspora: fix issue with diaspora where hublocs without hubloc_hash were stored
|
||||
|
||||
|
||||
Hubzilla 5.0.1 (2020-11-12)
|
||||
- Fix share title size
|
||||
- Fix issue where hublocs could get mixed up between different protocols
|
||||
|
||||
Addons
|
||||
- Pubcrawl: implement authenticated profile fetches which are now partly required in mastodon
|
||||
- Sse: call xchan_query() just once per item
|
||||
- Pubcrawl: reject messages where sender is not the author if ld-signature is not ok
|
||||
|
||||
|
||||
Hubzilla 5.0 (2020-11-05)
|
||||
- Remove unmaintained and deprecated schemas
|
||||
- Deprecate HTML5_Parser library
|
||||
- Implement results caching for public tag and profile categories fetching
|
||||
- Deprecate $a variable for *_plugin_admin() and *_plugin_admin_post()
|
||||
- Support remote host cache directives on profile photo fetching
|
||||
- Disable community tags until it is agreed upon on how to implement in zot6 or activitypub
|
||||
- Improve home install setup script
|
||||
- Cryptojs moved to addon
|
||||
- Implement "more encryption" feature with the SJCL library
|
||||
- Add minimum form lifetime check
|
||||
- Improve updateConvItems() performance
|
||||
- Improve infinite scroll experience
|
||||
- Introduce a software bill of material (wip)
|
||||
- Implement new forum behaviour (direct-message a forum to post on its wall) for cross-plattform forum compatibility
|
||||
- Allow apps to be both pinned and starred independently
|
||||
- Add images load status to spinnner if preload images is enabled
|
||||
- Deprecate premium channel app
|
||||
- Allow to set different values for left and right aside width in $theme.php
|
||||
- Display complete permission info only to channel owner
|
||||
- Set CURLOPT_ENCODING to empty string so that compressed content will be uncompressed
|
||||
- Force browser photo revalidation
|
||||
- Deprecate ACTIVITY_OBJ_FILE and ACTIVITY_OBJ_WIKI in favour of other object types (Document, Audio, Video)
|
||||
- Use $mid as plink to prevent to long plinks
|
||||
- Handle some basic friendica attachment bbcodes
|
||||
- Deprecate is_edit_activity()
|
||||
- Deprecate voting feature in favour of polls
|
||||
- Show event timezone if it differs from the channel timezone
|
||||
- Avoid multiple run of expiry procedure on large sites
|
||||
- Implement zot6 as the primary protocol
|
||||
- Introduce polls
|
||||
- Provide titles for wiki links markup
|
||||
- Implement DAV calendars sync with clones
|
||||
- Optional events and poll filters for mod network
|
||||
- Add new addon hook get_banner
|
||||
- Provide tools to deal with spam channels for primary directory admin
|
||||
- Introduce pinned posts for mod channel
|
||||
- Refactor notifications to utilize server sent events
|
||||
- Provide more descriptive connection status icons
|
||||
|
||||
|
||||
Bugfixes
|
||||
- Fix issue where interrupted uploads could not be resumed
|
||||
- Fix photo sync issue between clones
|
||||
- Fix issue where profile photos were fetched for unknown channels
|
||||
- Apply channel name changes to all associated xchans
|
||||
- Show unchecked box in connedit if value is false
|
||||
- Reset their_perms before setting new permissions to reflect permission retractions on local hub
|
||||
- Respect advanced profile setting in sexual preference selector
|
||||
- Do not allow invite codes to be reused unlimited times
|
||||
- Fix issue with quoted hashtags/mentions
|
||||
- Fix issue generating photo thumbnails when uploaded via davfs
|
||||
- Do not call System::get_platform_name() within t() unless needed
|
||||
- Fix wrong URL detection with Markdown support enabled
|
||||
- Fix once cached embedded content is used and stored forever
|
||||
|
||||
Addons
|
||||
- Pubcrawl: fix issue where http signatures were not verified
|
||||
- Pubcrawl: fix issue where private keys were lost from storage
|
||||
- Pubcrawl: add host to signed headers (required by mastodon 3.2.1)
|
||||
- Diaspora: remove relay@relay.iliketoat.net as default relay (it does not exist anymore)
|
||||
- Diaspora: provide UI for admin to configure relay
|
||||
- Diaspora: move the-federation.info registration to statistics addon
|
||||
- Deprecate $a variable for *_plugin_admin() and *_plugin_admin_post()
|
||||
- Chess: moved to addons-unmaintained repository
|
||||
- Introduce cryptojs addon to allow decryption of legacy e2ee notes
|
||||
- Introduce the hide aside addon - fade out aside areas after a while when using endless scroll
|
||||
- Gallery: only show first row of images in the preview
|
||||
- Gallery: restrict height of images to divmore_height
|
||||
- Diaspora: make sure we only provide strings for unxmlify()
|
||||
- Pubcrawl: fix federation with pixelfed
|
||||
- Pubcrawl: dismiss announce if we already have the original item
|
||||
- Gallery: implement view_storage permission for channel_apps()
|
||||
- Cart: order currency param must be added to the sdk script url
|
||||
- Diaspora utilize Lib/Connect
|
||||
- Cart: utilize Lib/Connect
|
||||
- Cart: add per item and per order customer data entry
|
||||
- Pubcrawl: implement polls
|
||||
- Chord Generator: moved to addons-unmaintained repository
|
||||
- Custom Home: moved to addons-unmaintained repository
|
||||
- Flattr Widget: moved to addons-unmaintained repository
|
||||
- Friendica Photo Migrator: moved to addons-unmaintained repository
|
||||
- Jappix Mini: moved to addons-unmaintained repository
|
||||
- Mahjongg: moved to addons-unmaintained repository
|
||||
- Torch: moved to addons-unmaintained repository
|
||||
- Tour: moved to addons-unmaintained repository
|
||||
- Introduce navbanner_option addon
|
||||
- Pubcrawl: support image description
|
||||
- Queueworker: fix duplicate checking
|
||||
- Diaspora: fix dreport
|
||||
- Move legacy zot/diaspora mail frontend from core to mail addon
|
||||
- Diaspora: improve sql queries performance
|
||||
- Pubcrawl: introduce pubcrawl_activity_mod_init()
|
||||
- Twitter: replace Hubzilla bookmark with unicode icon
|
||||
- Pubcrawl: add sys channel to local subscribers
|
||||
- Pubcrawl: deal with arrays in attributedTo
|
||||
- Workflow: various fixes
|
||||
- Channelreputation: various fixes
|
||||
- Introduce SSE addon to provide realtime notifications utilizing server sent events
|
||||
|
||||
|
||||
Hubzilla 4.6 (2019-12-04)
|
||||
- Improve opengraph support for channels
|
||||
- Add opengraph support for articles
|
||||
- Update abook_connected for RSS feeds only if handle_feed() returned success
|
||||
- Do not embed PDF files by default but allow to enabled this feature in security options
|
||||
- Check if file exists before we include it in the router
|
||||
- Update jquery to version 3.4.1
|
||||
- Update composer libraries
|
||||
- Remove old and unused javascript libraries
|
||||
- Improved BBcode to Markdown conversion
|
||||
- Introduce inline SVG support via BBcode
|
||||
- Sanitize title on Atom/RSS feed import
|
||||
- Improved HTTP headers cache support for photos
|
||||
- Add date headers to signed headers
|
||||
- Add check if item['tag'] is an array
|
||||
- Add hook comments_are_now_closed for addons to override date based comment closure
|
||||
- Change mysql schema for item.llink and item.plink for new installs from char(191) to text
|
||||
- Improved photo cache expiration
|
||||
- Improved plural function processing on translation strings creation from .po file with util/po2php utlility
|
||||
- Improved support for CDN/Infrastructure caching (especially profile images)
|
||||
- New japanese translation
|
||||
- Add connect button for non-zot networks not connected in current location
|
||||
- Allow to send forum channels wall2wall or sent by mentions post to external sites via addons
|
||||
- Allow addons to process forum posts published through mentions
|
||||
- Improved internal routing for ActivityPub messages
|
||||
- Improved admin documentation
|
||||
- Add ITEM_TYPE_CUSTOM and hooks to permit addons to create and distribute custom item types
|
||||
- Support "comment policy" in Zot6 communications
|
||||
- Add selected text as quote on reply if comment button is used
|
||||
- Add more nofollow tags to links to discourage backlink farmers
|
||||
- Improved conversion of emoji reactions from zot to zot6
|
||||
- Add CardDAV/CalDAV autodiscovery
|
||||
- Label source project of zotfeed since it is not completely compatible across projects
|
||||
- Update homeinstall script
|
||||
|
||||
Bugfixes
|
||||
- Fix once cached embedded content is used and stored forever
|
||||
- Fix wildcard tag issue
|
||||
- Fix duplicate attachment in jot fileupload
|
||||
- Fix regression with audio file upload
|
||||
- Fix can not edit menu name or title (#1402)
|
||||
- Fix pagination encoding issue for some server setups
|
||||
- Fix Zap->Hubzilla event title compatibility
|
||||
- Fix event timezones for Zot6
|
||||
- Fix missing summary in mod article_edit
|
||||
- Fix PHP warning failed to write session data using user defined save handler
|
||||
- Fix possible thumbnails distortion on rebuild with util/thumbrepair utility
|
||||
- Fix issues with image import to zot6
|
||||
- Fix attachment permissions on clonned channels sync
|
||||
- Fix entries without sitekey returned from DB in queue_deliver() and Lib/Queue
|
||||
|
||||
Addons
|
||||
- Twitter: send tweet even if attached image uploading was unsuccessful
|
||||
- Livejournal: add link to original post option
|
||||
- Flashcards: update to version 2.08
|
||||
- Pubcrawl: compatibility changes to support pixelfed
|
||||
- Cart: update paypal button to API v2
|
||||
- Photocache: rework for speed and lower memory consumption
|
||||
- Photocache: etag support for cached photos
|
||||
- Photocache: purge cache on addon uninstall
|
||||
- Openstreetmap: fix regression if no default values set
|
||||
- Livejournal: allow send posts from non channel owner
|
||||
- Pubcrawl: fix event timezones
|
||||
- Pubcrawl: better ActivityPub channel URL detection
|
||||
- Pubcrawl: fix comments delivery for other channels on the same hub
|
||||
- New addon "workflow" with initial basic "issue tracker" capability
|
||||
|
||||
|
||||
Hubzilla 4.4.1 (2019-08-16)
|
||||
- Fix wrong profile photo displayed when previewing and editing profiles
|
||||
- Fix regression from 4.4 which prevented encrypted signatures from being used for encrypted messages
|
||||
- Fix typo in queueworker addon which broke filtering of duplicate work
|
||||
|
||||
|
||||
Hubzilla 4.4 (2019-08-13)
|
||||
- Change primary directory from zotadel.net to hub.netzgemeinde.eu (requested by zotadel admin)
|
||||
- Add Russian context help files
|
||||
- Replace plink URL with share tag if possible
|
||||
- Catch and exclude trailing punctuation while URL embedding
|
||||
- Do not limit channel if service class property value is set to zero
|
||||
- Streamline keyId and creator/actor
|
||||
- Add daemon_master_summon hook
|
||||
- Serve static files directly if not caught by web server
|
||||
- Update cacert.pem
|
||||
- Calendar: allow different date/time format inputs
|
||||
- Calendar: hide timezone select for allday events
|
||||
⁻ Add opengraph meta info to channel page
|
||||
- Begin directory migration to zot6
|
||||
- Support zot and zot6 in social graph operations
|
||||
- Lowlevel support for zot6 direct messages
|
||||
- Consolidate HTTP signatures
|
||||
- Allow api login by address or url
|
||||
- Provide auto redirect from zot6 /item permalinks
|
||||
- Export all items except photos in channel_export_items_date()
|
||||
- Calendar: clicking a day or week number will now open the day or week view
|
||||
- Remove cached photo location directory on delete if empty
|
||||
- Include zot6 hubs in the Grid scope
|
||||
- Fix os_path replace for thumbnails
|
||||
- Avoid to process original images using storeThumbnail()
|
||||
|
||||
Bugfixes
|
||||
- Fix URLs on imported item taxonomy
|
||||
- Fix admin not allowed to delete any item
|
||||
- Fix webfiunger issue with URLs containing an @
|
||||
- Fix missing object in emoji reactions
|
||||
- Fix appschema to include diaspora:guid
|
||||
- Fix zotfinger in update_directory_entry()
|
||||
- Fix incorrect media type on links for photo objects
|
||||
- Fix mid not dbesc'd in item_store()
|
||||
- Fix calendar encoding issues
|
||||
|
||||
Addons
|
||||
- twitter: various rendering improvements
|
||||
- cavatar: fix wrong image mimetype
|
||||
- gravatar: fix wrong image mimetype
|
||||
- Add license file
|
||||
- pubcrawl: make repeats render like wall to wall posts
|
||||
- pubcrawl: fix pubcrawl_import_author() sometimes returning a non activitypub xchan
|
||||
- pubcrawl: use Lib/Activity for taxonomy en/decoding
|
||||
- pubcrawl: fix wrong uuid in like activity
|
||||
- pubcrawl: fix issue with encoding hashtags
|
||||
- openstreetmap: use https URLs by default
|
||||
- queueworker: refactor and efficiency improvements
|
||||
- pubcrawl: use unique IDs for follow and accept activities
|
||||
- pubcrawl: implement thread completion
|
||||
- pubcrawl: implement delete activity
|
||||
- photocache: reduce the size of the photo cache subdirectories tree
|
||||
- photocache: use html_entity_decode() for cached photo URL
|
||||
- diaspora: fix possible issue with diaspora relay not initializing
|
||||
|
||||
|
||||
Hubzilla 4.2.1 (2019-06-17)
|
||||
- Deprecate mod events
|
||||
- Revisit mod cal
|
||||
- Fix issues with deletion of linked items and resources
|
||||
- Fix zot6 delete issue
|
||||
- Fix attach sync issue
|
||||
- Remove sizeRangeSuffixes in justified gallery wrapper
|
||||
- Fix storageconv issue with postgres
|
||||
- Fix embedphotos image size
|
||||
- pubcrawl: use URI instead of object for actor url
|
||||
- diaspora: adjust loglevel
|
||||
- gallery: remove workaround for margin issue which has been fixed upstream
|
||||
- cart: warn about unsaved changes
|
||||
|
||||
|
||||
Hubzilla 4.2 (2019-06-04)
|
||||
- Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets
|
||||
- Update mod cal to reflect changes in the calendar app
|
||||
- Improve timezone detection for CalDAV calendars
|
||||
- Add mention support to event description in channel calendar
|
||||
- Update jgrowl library
|
||||
- Do not try to oembed URLs without embed tags
|
||||
- Optimise pdf oembed processing
|
||||
- Add form security token to mod register
|
||||
- Replace URLs for mod gallery, mod photos and mod photo on cloned channel post sync
|
||||
- Update justified gallery library
|
||||
- Update bootstrap libraries
|
||||
- Use "cache" flag for bbcode() on content destined for zot6
|
||||
- Improve DB indexing
|
||||
- Drop deprecated columns from channel the table
|
||||
- Replace own image URL in clonned channel posts
|
||||
- Improve DB update handling
|
||||
- Improve item deletion when a contact was removed
|
||||
- Zot6 compatibility for emoji reactions
|
||||
- Add threaded comments support (disabled by default)
|
||||
- Improve xmlify()/unxmlify() performance
|
||||
- Update blueimp/jquery-file-uplad library
|
||||
- Update sabre/vobject library
|
||||
- Various doco updates
|
||||
- Implement remove profile photo button (reset to default photo)
|
||||
- Implement remove cover photo button
|
||||
- Update the homeinstall script
|
||||
- Add command line tool for photo thumbnails storage conversion
|
||||
- Implement option to store photo thumbnails in filesystem instead of DB
|
||||
|
||||
Bugfixes
|
||||
- Fix category widget when using articles
|
||||
- Fix live update not triggering in mod search
|
||||
- Fix encoded URLs in code blocks
|
||||
- Fix wiki headers not escaped
|
||||
- Fix possible xchan protocol confusion in new_contact()
|
||||
- Fix xchan_url not displayed if xchan_addr not available
|
||||
- Fix suggestion ordering in mod directory
|
||||
- Fix event attachment delivery to zot6
|
||||
|
||||
Addons
|
||||
- pubcrawl: improve friendica compatibility by adding the nonstandard diaspora:guid field
|
||||
- pubcrawl: initial suport for events
|
||||
- pubcrawl: improve permalink detection
|
||||
- flashcards: fix moving learn buttons if viewport sizes changes
|
||||
- flashcards: Move card details to the bottom of a card
|
||||
- upgrade_info: provide links to changelog
|
||||
- photocache: do not save filename for cached photos
|
||||
- pubcrawl: save local comment activitypub payload in iconfig to be used for relay
|
||||
- flashcards: UI improvements in box settings
|
||||
- pubcrawl: implement profile update messages
|
||||
- pubcrawl: use URI instead of object for actor
|
||||
- flashcards: fix jumping sync button
|
||||
- pubcrawl: add threaded comments support
|
||||
- pubcrawl: ignore target encoding errors
|
||||
- pubcrawl: format photo items for activitypub
|
||||
|
||||
|
||||
Hubzilla 4.0.3 (2019-04-26)
|
||||
- Add attachments to zot6 event objects
|
||||
- Add zot6 to federated transports
|
||||
- Update import/export to handle zot6 hublocs and xchans
|
||||
- Update fix_system_urls() to handle zot6 hublocs
|
||||
- Fix infinite loop using postgres as backend
|
||||
- Fix magic auth in combination with zot6
|
||||
- Fix check for required PHP version
|
||||
- Diaspora: favour diaspora protocol identities over others with same hubloc or xchan address
|
||||
|
||||
|
||||
Hubzilla 4.0.2 (2019-04-08)
|
||||
- Port cdav calendar to fullcalendar version 4
|
||||
- Fix perms_pending not evaluated correctly
|
||||
- Fix return wrong profile photo modification date by plugin
|
||||
- Fix suggestion widget using feature_enabled still
|
||||
- Fix check service class limits when syncing files
|
||||
- Remove xchan_instance_url from notifier query - it is not used anymore
|
||||
- Implement remove cover photo functionality
|
||||
- Fix z6_discover() and create a zot6 hubloc on import if applicable
|
||||
- Add backend support for connections ordering
|
||||
- Deduplicate items in item_store() by uuid if we got one otherwise by mid
|
||||
- Add ITEM_TYPE_CUSTOM support to mod display
|
||||
- Fix mod subthread on sys channel items
|
||||
- Fix "recipient not found" dreport spaming with own xchan
|
||||
- Fix wrong variables in dirsearch
|
||||
- Fix 48 hours timeframe check in mod changeaddr
|
||||
- Fix wrong variable in Libsync
|
||||
- Pubcrawl: revert adding additional receivers to comments
|
||||
- Diaspora: fix intro received when being banned
|
||||
- Pubcrawl: add diaspora:guid from friendica AP posts for deduplication
|
||||
- Diaspora: fix friendica plink
|
||||
- Photocache: fix issue with spaces and quotes in original filenames
|
||||
|
||||
|
||||
Hubzilla 4.0.1 (2019-03-21)
|
||||
- Fix permissions not getting decrypted on follow
|
||||
- Add option to add a poster to the video bbcode
|
||||
- Fix SQL performance issue with queries including thr_parent
|
||||
- Fix share encoding issue between hz and zap
|
||||
- Fix edge case in unsupported advisory privacy
|
||||
- Messagefilter enhancements
|
||||
- Fix XSS issues
|
||||
- Clone systems apps to the extent possible
|
||||
- Auto-configure imagick thumbnail binary during setup if possible
|
||||
- Fix array not unserialized in util/service_class
|
||||
- Add phpmd and phpcs to composer require-dev for code linting
|
||||
- Fix issue with email encoding
|
||||
- Fix signature issue for zot6 content imported from zotfeeds to hubzilla
|
||||
- Find unregistered z6 clones on hubzilla sites
|
||||
- Add zot6 to clonable networks
|
||||
- Add owner permission checks to AS item fetch
|
||||
- Perform zot6 discovery in import_author_xchan
|
||||
- Fix authenticated fetches
|
||||
- Port zot_record_preferred() from zap
|
||||
|
||||
Addons:
|
||||
- Pubcrawl: deliver comments to abook contacts and thread participants
|
||||
- Pubcrawl: fix can_comment_on_post()
|
||||
- Deliverynotice: do not save empty postopts
|
||||
- Gravatar: fix URL and use z_fetch_url()
|
||||
- Pubcrawl: improve SQL queries in pubcrawl_item_mod_init()
|
||||
- Pubcrawl: fix authenticated item fetch
|
||||
|
||||
|
||||
Hubzilla 4.0 (2019-03-08)
|
||||
- Add CURLOPT_CONNECTTIMEOUT option
|
||||
- Allow parameters as final path argument in API router
|
||||
@@ -202,7 +635,7 @@ Hubzilla 3.8.3 (2018-11-05)
|
||||
- Fix forum notifications count not correct
|
||||
- Fix gallery addon which broke mod apps in some situations
|
||||
- Fix wiki_list widget not working on every page respectively level
|
||||
|
||||
|
||||
|
||||
Hubzilla 3.8.2 (2018-10-29)
|
||||
- Merge unmerged changes from dev into master
|
||||
@@ -218,7 +651,7 @@ Hubzilla 3.8.2 (2018-10-29)
|
||||
- Look for for matches in the entire string when suggesting emojis
|
||||
- Add [summary] bbcode to autocomplete list
|
||||
- Update blueimp_upload to version 9.23
|
||||
- Update spanish strings
|
||||
- Update spanish strings
|
||||
|
||||
Addons
|
||||
- Cart: don't allow items to be added unless user is logged into the Grid.
|
||||
@@ -276,7 +709,7 @@ Hubzilla 3.8 (2018-10-19)
|
||||
- Sanitise vcard fields
|
||||
- Don't sync system apps
|
||||
|
||||
|
||||
|
||||
Bugfixes
|
||||
- Fix issue with timeago plurals
|
||||
- Fix issue with HTTP signatures
|
||||
@@ -335,7 +768,7 @@ Hubzilla 3.8 (2018-10-19)
|
||||
Hubzilla 3.6 (2018-07-25)
|
||||
- Update jquery.timeago library
|
||||
- Implement Hookable CSP
|
||||
- ActivityStreams: accept header changes to support plume
|
||||
- ActivityStreams: accept header changes to support plume
|
||||
- Streamline inconsistencies in addon naming
|
||||
- SECURITY: hash the session_id in logs
|
||||
- Update justified gallery library
|
||||
@@ -348,9 +781,9 @@ Hubzilla 3.6 (2018-07-25)
|
||||
- Make droping posts of removed connections more memory efficient
|
||||
- Refactor getOutainfo() for DAV storage
|
||||
- Optionally report total available space when uploading
|
||||
- SECURITY: provide option to disable the cloud 'root' directory and make the cloud module require a target channel nickname
|
||||
- SECURITY: provide option to disable the cloud 'root' directory and make the cloud module require a target channel nickname
|
||||
- Add plink and llink to viewsource
|
||||
- Add new 'filter by name' feature
|
||||
- Add new 'filter by name' feature
|
||||
- Remove network tabs
|
||||
- New activity filter widget
|
||||
- New activity order widget
|
||||
@@ -392,8 +825,8 @@ Hubzilla 3.6 (2018-07-25)
|
||||
- Fix sys channels visible in dirsearch
|
||||
- Fix remote_self not working correctly
|
||||
- Fix photos not syncing properly if destination is a postgres site
|
||||
- Fix wrong hubloc_url for activitypub hublocs
|
||||
- Fix z_check_dns() for BSD
|
||||
- Fix wrong hubloc_url for activitypub hublocs
|
||||
- Fix z_check_dns() for BSD
|
||||
- Fix not null violation in oauth1
|
||||
- Fix DB issues with oauth2 on postgresql
|
||||
- Fix 'anybody authenticated' not correctly handled in can_comment_on_post()
|
||||
@@ -955,10 +1388,10 @@ Hubzilla 2.6.2 (2017-08-31)
|
||||
Hubzilla 2.6.1 (2017-08-18)
|
||||
- Fix a regression with dav clients
|
||||
- Raise install requirements
|
||||
|
||||
|
||||
Plugins/Addon
|
||||
- Diaspora: fix PHP warning
|
||||
- GNU-Social: fix PHP warning
|
||||
- GNU-Social: fix PHP warning
|
||||
|
||||
|
||||
Hubzilla 2.6 (2017-08-16)
|
||||
@@ -966,18 +1399,18 @@ Hubzilla 2.6 (2017-08-16)
|
||||
- Consolidate disable_discover_tab config
|
||||
- Fix some bbcode to markdown conversion issues
|
||||
- Improved finding of recursive attachment permissions
|
||||
- Smaller line-height for notification badges
|
||||
- Smaller line-height for notification badges
|
||||
- Bluegrid schema removed - will be added again if someone is willing to maintain it
|
||||
- Improved file_activity()
|
||||
- DB - add index for item.obj_type
|
||||
- Add options flag to bb_to_markdown() so we can distinguish between diaspora use and other use and therefore filter and adjust content selectively
|
||||
- Close the apps-menu if the notifications-menu is open and vice versa
|
||||
- Close the apps-menu if the notifications-menu is open and vice versa
|
||||
- Remove redundant call to jquery ready function in photo albums view
|
||||
- Remove borders from navbar toggler in mobile view
|
||||
- Improve the formatting of shares when converting from bbcode to markdown
|
||||
- Suppress fopen errors from dav
|
||||
- Make local channel (not our own) nav menus appear similar to what we are used from remote channels
|
||||
- Indicate the selected channel in the dropdown menu if the feature is enabled
|
||||
- Indicate the selected channel in the dropdown menu if the feature is enabled
|
||||
- Provide a mechanism to mark apps active in the app tray
|
||||
- Allow wildcard tag and category searches
|
||||
- Improved installer
|
||||
@@ -989,7 +1422,7 @@ Hubzilla 2.6 (2017-08-16)
|
||||
- Update htmlpurifier to version 4.9.3
|
||||
- Update sabre/http to version 4.2.3
|
||||
- Add optimize-autoloader to composer config
|
||||
- Missing abook_{my,their}_perms in pg schema and missing keys in mysql schema
|
||||
- Missing abook_{my,their}_perms in pg schema and missing keys in mysql schema
|
||||
- Provide a gender icon on the profile sidebar within reason
|
||||
- Provide more comprehensible information on the admin summary page
|
||||
- Upgrade blueimp from 9.8 to 9.18
|
||||
@@ -1055,7 +1488,7 @@ Hubzilla 2.6 (2017-08-16)
|
||||
Cdav addon moved to core
|
||||
head_add_css() needs a preceding '/' to find files in the addons dir
|
||||
New addon code syntax highlighting (moved from core to addon)
|
||||
Pubsubhubbub: specify a minimum number of records - otherwise it defaults to zero
|
||||
Pubsubhubbub: specify a minimum number of records - otherwise it defaults to zero
|
||||
|
||||
|
||||
Hubzilla 2.4 (2017-05-31)
|
||||
@@ -1409,10 +1842,10 @@ Hubzilla 1.14 (2016-10-13)
|
||||
- Start grouping addons by server_role
|
||||
|
||||
Hubzilla 1.12
|
||||
- extensible permissions so you can create a new permission rule such as "can write to my wiki" or "can see me naked".
|
||||
- guest access tokens can do anything you let them, including create posts and administer your channel
|
||||
- extensible permissions so you can create a new permission rule such as "can write to my wiki" or "can see me naked".
|
||||
- guest access tokens can do anything you let them, including create posts and administer your channel
|
||||
- ACLs can be set on files and directories prior to creation.
|
||||
- ACL tool can now be used in multiple forms within a page
|
||||
- ACL tool can now be used in multiple forms within a page
|
||||
- a myriad of new drag/drop features (drop files or photos into /cloud or a post, or drop link into a post or comment, etc.)
|
||||
- multiple file uploads
|
||||
- improvements to website import
|
||||
@@ -1437,7 +1870,7 @@ Hubzilla 1.10
|
||||
Wiki:
|
||||
Lots of enhanced functionality, usability improvements, and bugfixes from v1.8
|
||||
Turned into an optional feature (default on) but disabled in UNO
|
||||
Sync:
|
||||
Sync:
|
||||
Items are now relocated (links patched) when syncing to clones
|
||||
Access Tokens:
|
||||
New feature - allows members to create access controlled guest logins and create/share 'dropbox' style links to protected resources.
|
||||
@@ -1445,7 +1878,7 @@ Hubzilla 1.10
|
||||
Use icons instead of iconic text constructs
|
||||
Only request geolocation permission when creating a post, not on page load
|
||||
provide 'redeliver' option on Delivery Report page for when things really stuff up
|
||||
CalDAV/CardDAV management pages with heaps of functionality
|
||||
CalDAV/CardDAV management pages with heaps of functionality
|
||||
Lib:
|
||||
z_fetch_url() updated to accept different request methods and request bodies
|
||||
item_store(), item_store_update() now return the stored items
|
||||
@@ -1469,7 +1902,7 @@ Hubzilla 1.10
|
||||
issues with 'use existing photo' for profile photo
|
||||
layout editor "list all layouts" returned empty
|
||||
oembed - better detect video file URLs so they aren't loaded into memory.
|
||||
handcrafted bbcode tables could end up with way too much whitespace due to CRLF translation
|
||||
handcrafted bbcode tables could end up with way too much whitespace due to CRLF translation
|
||||
refresh permissions whitescreen in 1.8
|
||||
force immediate profile photo update on local site
|
||||
regression: 'save bookmarks' post action missing
|
||||
@@ -1494,7 +1927,7 @@ Hubzilla 1.8
|
||||
Documentation:
|
||||
Clarify privacy rights of commenters w/r/t conversation owners, as this policy is network dependent.
|
||||
Wiki (Git backed):
|
||||
Brand new feature. We'll call it experimental until it has undergone a bit more testing.
|
||||
Brand new feature. We'll call it experimental until it has undergone a bit more testing.
|
||||
Account Cloning:
|
||||
Regression on clone channel creation created a new channel name each time.
|
||||
New issue (fixed) with directory creation on cloned file content
|
||||
@@ -1517,7 +1950,7 @@ Hubzilla 1.8
|
||||
Experimental PDO database driver
|
||||
Creation of Daemon Master class and port all daemon (background task) interfaces to use it
|
||||
Create separate class for each of 'Cron', 'Cron daily', and 'Cron weekly'.
|
||||
Always run a Cron maintenance task if not run in the last four hours
|
||||
Always run a Cron maintenance task if not run in the last four hours
|
||||
Refactor the template classes
|
||||
Refactor the ConversationItem mess into ThreadItem and ThreadStream
|
||||
Refactor Apps, Enotify, and Chat library code
|
||||
@@ -1525,7 +1958,7 @@ Hubzilla 1.8
|
||||
Created WebServer class for top level
|
||||
Remove mcrypt dependencies (deprecated in PHP 7.1)
|
||||
Remove all reserved (including merely 'not recommended') words as DB table column names
|
||||
Provide mutex lock on DB logging to prevent recursion under rare failure modes.
|
||||
Provide mutex lock on DB logging to prevent recursion under rare failure modes.
|
||||
Bugfixes:
|
||||
Remove db_close function on page end - not needed and will not work with persistent DB connections.
|
||||
Undefined ref_session_write
|
||||
@@ -1545,7 +1978,7 @@ Hubzilla 1.8
|
||||
CalDAV/CardDAV plugin provided
|
||||
Issue sending Diaspora 'like' activities from sources that did not propagate the DCV
|
||||
Allow 'superblock' to work across API calls from third party clients
|
||||
statistics.json: use 'zot' as protocol
|
||||
statistics.json: use 'zot' as protocol
|
||||
Issues fixed during testing of ability to follow Diaspora tags
|
||||
Parse issue with Diaspora reshare content
|
||||
Chess: moved to main repo, ported to 1.8
|
||||
@@ -1557,7 +1990,7 @@ Hubzilla 1.6
|
||||
Plugin hook interface adapted to call static class methods
|
||||
Context help improved dramatically with content for the most accessed pages.
|
||||
Reverted a compatibility change to support GNU-social events. We copied their feed format and their feed format is wrong (XML namespace collisions).
|
||||
Provide a querystring attribute to CSS/JS resources to avoid caching issues when our code changes (which is often).
|
||||
Provide a querystring attribute to CSS/JS resources to avoid caching issues when our code changes (which is often).
|
||||
Fix javascript detection and allow either positive or negative detection.
|
||||
Refactor the plugin hook registration procedure, provide 'unregister all' ability.
|
||||
Fix RSD (Real Simple Discovery) which has been broken for some time.
|
||||
@@ -1566,7 +1999,7 @@ Hubzilla 1.6
|
||||
Update font-awesome to 4.6.1
|
||||
Update SabreDAV to 3.0 (PHP version requirements prevent us from pushing it further at this time)
|
||||
Help text added to cmdline utilities config and pconfig
|
||||
Reworking of the database logging facility to avoid the rare but troublesome recursion when the log facility needed to query the DB internally to obtain config parameters.
|
||||
Reworking of the database logging facility to avoid the rare but troublesome recursion when the log facility needed to query the DB internally to obtain config parameters.
|
||||
Implement singleton delivery (emulate nomadic identity to singleton networks and services)
|
||||
Fix empty album name in photo activities when photo is stored in top level folder.
|
||||
Allow engineering units to be used in service class data size restrictions (400M, 1G, etc.)
|
||||
@@ -1574,7 +2007,7 @@ Hubzilla 1.6
|
||||
Admin interface provided to manage external resource repositories
|
||||
Oembed security reworked. Now all sources are filtered by default unless blocked.
|
||||
Remove the date-string version and use only STD_VERSION
|
||||
Add categories and categorisation filtering and the ability to edit all apps (including system apps) for a given channel
|
||||
Add categories and categorisation filtering and the ability to edit all apps (including system apps) for a given channel
|
||||
Ensure the ability to translate names of all system apps (except those provided in addons)
|
||||
Provide ability to add categories to content from channel sources
|
||||
Lots of work on the presentation of the ACL widget to enhance usability and intuitiveness
|
||||
@@ -1588,24 +2021,24 @@ Hubzilla 1.6
|
||||
Provide some extra security checks to import data and files to prevent mischief
|
||||
Block CalDAV/CardDAV namespace reserved words from being used as a channel nickname/redress since Sabre is somewhat inflexible in this regard
|
||||
Plugins:
|
||||
Diaspora
|
||||
markdown translator work needed to eradicate the Diaspora Comment Virus.
|
||||
Diaspora
|
||||
markdown translator work needed to eradicate the Diaspora Comment Virus.
|
||||
upgrade all inbound paths with the most recent protocol changes (several of these)
|
||||
convert 'diaspora_meta' (Diaspora Comment Virus) to iconfig and eradicate from sites with Diaspora disabled
|
||||
implement social relay and allow following tags
|
||||
upgrade statistics.json to NodeInfo. Currently hubzilla sites are tagged as 'redmatrix' because the NodeInfo schema lacks extensibility and project names are used to designate protocol compatibility rather than protocol names.
|
||||
Std-embeds
|
||||
New addon to allow a handful of corporate providers to run unfiltered embed code (youtube, vimeo, soundcloud)
|
||||
New addon to allow a handful of corporate providers to run unfiltered embed code (youtube, vimeo, soundcloud)
|
||||
Various:
|
||||
upgrade font-awesome icons and adapt a few addons to Objects and the new hook interface and new controller interface
|
||||
|
||||
|
||||
Hubzilla 1.4
|
||||
[This list may appear brief, but encompasses a huge amount of re-writing and re-factoring
|
||||
of the internal code structure to gain long-term performance and stability and provide a standard
|
||||
interface to alternate protocol federation plugins which were made possible by the UNO configuration.
|
||||
UNO is a configuration of hubzilla introduced in 1.3 with reduced complexity and which provides
|
||||
improved protocol federation potential to other networks by virtue of removing nomadic identity
|
||||
(which is not possible to model or work around using other network protocols).]
|
||||
UNO is a configuration of hubzilla introduced in 1.3 with reduced complexity and which provides
|
||||
improved protocol federation potential to other networks by virtue of removing nomadic identity
|
||||
(which is not possible to model or work around using other network protocols).]
|
||||
|
||||
Implement channel move operation for UNO configuration
|
||||
Remove bookmark references in UNO (which has no bookmarks by default)
|
||||
@@ -1628,10 +2061,10 @@ Hubzilla 1.4
|
||||
Rework detection of JavaScript to avoid reload penalty under normal operation
|
||||
Changed primary directory server to a hubzilla server
|
||||
Plugins:
|
||||
Diaspora - switch to alternate XML parser to avoid storing compound objects
|
||||
Diaspora - switch to alternate XML parser to avoid storing compound objects
|
||||
GNU-Social - Huge amounts of work, federation somewhat working now, several issues remain
|
||||
Friendica - Initial federation work (not yet published)
|
||||
|
||||
|
||||
Hubzilla 1.3
|
||||
Admin Security configuration page created which consolidates several previously hidden settings:
|
||||
Communication white/black lists
|
||||
@@ -1647,26 +2080,26 @@ Hubzilla 1.3
|
||||
"pubsites" module UI reworked
|
||||
item-meta ("iconfig") created which implements arbitrary storage for item metadata for plugins
|
||||
abook-meta ("abconfig") created which implements arbitrary storage for connection metadata for plugins
|
||||
"Strict transport security header" made optional as it conflicts with some existing Apache/nginx configurations
|
||||
"Hubzilla UNO" (Hubzilla with radically simplified and locked site settings) implemented as an install configuration.
|
||||
"Strict transport security header" made optional as it conflicts with some existing Apache/nginx configurations
|
||||
"Hubzilla UNO" (Hubzilla with radically simplified and locked site settings) implemented as an install configuration.
|
||||
.well-known directory conflict worked out to support LetsEncrypt cert ownership checks without disrupting webfinger and other internal uses of .well-known
|
||||
Lots of work on 'zcards' which are self-contained HTML representations of a channel including cover photos, profile photos, and some text information
|
||||
Long standing bug uncovered which failed to properly restrict the lower time limit for public feed requests
|
||||
A number of fixes to "readmore" to fix page jumping
|
||||
Bugfix: persons other than the channel owner who have permission to upload photos to a channel could not do so if the js_upload plugin/addon was enabled
|
||||
Siteinfo incorrectly identifying secondary directory servers
|
||||
Allow admin to set and lock features when UNO is configured
|
||||
Allow admin to set and lock features when UNO is configured
|
||||
Atom feeds: alter how events are formatted to be compatible with GNU-social
|
||||
Allow guest/visitor access to view personal calendar
|
||||
Moved several more classes to "composer format" and provided an autoloader.
|
||||
Bugfix: require existing password to change password
|
||||
Bugfix: allow relative_date() to be translated to Polish which has more than two plural forms.
|
||||
Bugfix: allow relative_date() to be translated to Polish which has more than two plural forms.
|
||||
Plugin API: add "requires" keyword to module header to indicate dependent addons
|
||||
ActivityStreams improvements and cleanup: photo and file activities
|
||||
UI cleanup for editing profile when multiple profiles enabled
|
||||
Removed the "markdown" feature as there are numerous issues and no maintainer.
|
||||
Provide "footer" bbcode to ease theming of post footer content
|
||||
Bugfix: install issues caused by composer code refactor and typo in postgres load file
|
||||
Bugfix: install issues caused by composer code refactor and typo in postgres load file
|
||||
Plugins:
|
||||
keepout - "block public on steroids"
|
||||
pubsubhubbub - provides PuSH support to Atom feeds, required for GNU-social federation
|
||||
@@ -1674,7 +2107,7 @@ Hubzilla 1.3
|
||||
Diaspora protocol - some work to ease migration to the new signing format
|
||||
Diaspost - disabled; numerous issues and no maintainer
|
||||
smileybutton - theme work and fixed compatibility with other jot-tools plugins
|
||||
|
||||
|
||||
|
||||
Hubzilla 1.2
|
||||
Provide extra HTTP security headers (several of them).
|
||||
@@ -1684,7 +2117,7 @@ Hubzilla 1.2
|
||||
Add locked features to siteinfo report to aid remote debugging
|
||||
Provide version compatibility checking to plugins (minversion, maxversion, and minphpversion)
|
||||
Account config storage
|
||||
Provide optional integrated registration and channel create form
|
||||
Provide optional integrated registration and channel create form
|
||||
cli utility for managing addons
|
||||
issue with sharing photo "items"
|
||||
cover photo manager: upload, crop, and store
|
||||
@@ -1706,7 +2139,7 @@ Hubzilla 1.2
|
||||
proc_run modified to use exec() instead of proc_open() - causing issues on some PHP installations
|
||||
remote delegation failure under a specific set of circumstances which we were finally able to duplicate
|
||||
Delegation section of Channel Manager was missing names and contained useless notification icons.
|
||||
Change "expire" channel setting to show system limit if there is one.
|
||||
Change "expire" channel setting to show system limit if there is one.
|
||||
Regression: provide a one-click ignore of pending connection
|
||||
Config to control directory keyword generation on client and server.
|
||||
"Collections" renamed to "Privacy Groups", documentation improved
|
||||
@@ -1759,11 +2192,11 @@ Hubzilla 1.1
|
||||
Addons/Plugins:
|
||||
Pageheader addon ported from Friendica
|
||||
Hubwall (allow admin to send email to all accounts on this hub) created
|
||||
GNU-social - queueing added
|
||||
Diaspora - fixes for various failures to update profile photos, updates to queue API
|
||||
GNU-social - queueing added
|
||||
Diaspora - fixes for various failures to update profile photos, updates to queue API
|
||||
Cross Domain Authenticated Chess (Andrew Manning's repository)
|
||||
|
||||
And... the normal "lots of bugs fixed, translations updated, and documentation improved"
|
||||
|
||||
|
||||
|
||||
And... the normal "lots of bugs fixed, translations updated, and documentation improved"
|
||||
|
||||
|
||||
|
||||
|
||||
11
LICENSE
11
LICENSE
@@ -1,4 +1,5 @@
|
||||
Copyright (c) 2010-2018 the Hubzilla Community
|
||||
Copyright (c) 2019 Hubzilla Community
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -8,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
32
SBOM.md
Normal file
32
SBOM.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Hubzilla Software Bill of Materials - WIP
|
||||
|
||||
|Name|Version|License|Source|
|
||||
|----|-------|-------|------|
|
||||
|blueimp/jquery-file-upload|10.31.0.0|MIT|https://github.com/vkhramtsov/jQuery-File-Upload.git|
|
||||
|bshaffer/oauth2-server-php|1.11.1.0|MIT|https://github.com/bshaffer/oauth2-server-php.git|
|
||||
|commerceguys/intl|1.0.5.0|MIT|https://github.com/commerceguys/intl.git|
|
||||
|desandro/imagesloaded|4.1.4.0|MIT|https://github.com/desandro/imagesloaded.git|
|
||||
|ezyang/htmlpurifier|4.13.0.0|LGPL-2.1-or-later|https://github.com/ezyang/htmlpurifier.git|
|
||||
|league/html-to-markdown|4.10.0.0|MIT|https://github.com/thephpleague/html-to-markdown.git|
|
||||
|lukasreschke/id3parser|0.0.3.0|GPL|https://github.com/LukasReschke/ID3Parser.git|
|
||||
|michelf/php-markdown|1.9.0.0|BSD-3-Clause|https://github.com/michelf/php-markdown.git|
|
||||
|paragonie/random_compat|9.99.99.0|MIT|https://github.com/paragonie/random_compat.git|
|
||||
|pear/text_languagedetect|1.0.0.0|BSD-2-Clause|https://github.com/pear/Text_LanguageDetect.git|
|
||||
|psr/log|1.1.3.0|MIT|https://github.com/php-fig/log.git|
|
||||
|ramsey/uuid|3.9.3.0|MIT|https://github.com/ramsey/uuid.git|
|
||||
|sabre/dav|4.1.1.0|BSD-3-Clause|https://github.com/sabre-io/dav.git|
|
||||
|sabre/event|5.1.0.0|BSD-3-Clause|https://github.com/sabre-io/event.git|
|
||||
|sabre/http|5.1.0.0|BSD-3-Clause|https://github.com/sabre-io/http.git|
|
||||
|sabre/uri|2.2.0.0|BSD-3-Clause|https://github.com/sabre-io/uri.git|
|
||||
|sabre/vobject|4.3.1.0|BSD-3-Clause|https://github.com/sabre-io/vobject.git|
|
||||
|sabre/xml|2.2.1.0|BSD-3-Clause|https://github.com/sabre-io/xml.git|
|
||||
|simplepie/simplepie|1.5.5.0|BSD-3-Clause|https://github.com/simplepie/simplepie.git|
|
||||
|smarty/smarty|3.1.36.0|LGPL-3.0|https://github.com/smarty-php/smarty.git|
|
||||
|symfony/polyfill-ctype|1.13.1.0|MIT|https://github.com/symfony/polyfill-ctype.git|
|
||||
|twbs/bootstrap|4.5.2.0|MIT|https://github.com/twbs/bootstrap.git|
|
||||
|fullcalendar/fullcalendar|4.4.2.0|MIT|https://github.com/fullcalendar/fullcalendar.git|
|
||||
|miromannino/Justified-Gallery|3.8.1.0|MIT|https://github.com/miromannino/Justified-Gallery.git|
|
||||
|fengyuanchen/cropperjs|1.5.7.0|MIT|https://github.com/fengyuanchen/cropperjs.git|
|
||||
|ForkAwesome/Fork-Awesome|1.1.7.0|MIT,SIL OFL,CC BY 3.0|https://github.com/ForkAwesome/Fork-Awesome.git|
|
||||
|leafo/sticky-kit|1.1.2.0|MIT|https://github.com/leafo/sticky-kit.git|
|
||||
|jquery/jquery|3.5.1.0|MIT|https://github.com/jquery/jquery.git|
|
||||
@@ -100,6 +100,7 @@ class PermissionRoles {
|
||||
'post_mail', 'post_like' , 'republish', 'chat'
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['channel_type'] = 'group';
|
||||
|
||||
break;
|
||||
|
||||
@@ -113,6 +114,7 @@ class PermissionRoles {
|
||||
'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'tag_deliver',
|
||||
'post_mail', 'post_like' , 'chat' ];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['channel_type'] = 'group';
|
||||
|
||||
break;
|
||||
|
||||
@@ -132,6 +134,7 @@ class PermissionRoles {
|
||||
$ret['limits']['view_storage'] = PERMS_SPECIFIC;
|
||||
$ret['limits']['view_pages'] = PERMS_SPECIFIC;
|
||||
$ret['limits']['view_wiki'] = PERMS_SPECIFIC;
|
||||
$ret['channel_type'] = 'group';
|
||||
|
||||
break;
|
||||
|
||||
@@ -187,6 +190,7 @@ class PermissionRoles {
|
||||
'post_mail', 'post_like' , 'republish', 'chat', 'write_wiki'
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['channel_type'] = 'group';
|
||||
|
||||
break;
|
||||
|
||||
|
||||
@@ -283,4 +283,15 @@ class Permissions {
|
||||
return ( [ 'perms' => $my_perms, 'automatic' => $automatic ] );
|
||||
}
|
||||
|
||||
}
|
||||
static public function serialise($p) {
|
||||
$n = [];
|
||||
if($p) {
|
||||
foreach($p as $k => $v) {
|
||||
if(intval($v)) {
|
||||
$n[] = $k;
|
||||
}
|
||||
}
|
||||
}
|
||||
return implode(',',$n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
|
||||
require_once('include/hubloc.php');
|
||||
|
||||
class Checksites {
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
class Cron {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
@@ -36,10 +38,14 @@ class Cron {
|
||||
|
||||
Master::Summon(array('Poller'));
|
||||
|
||||
// maintenance for mod sharedwithme - check for updated items and remove them
|
||||
|
||||
require_once('include/sharedwithme.php');
|
||||
apply_updates();
|
||||
/**
|
||||
* Chatpresence: if somebody hasn't pinged recently, they've most likely left the page
|
||||
* and shouldn't count as online anymore. We allow an expection for bots.
|
||||
*/
|
||||
q("delete from chatpresence where cp_last < %s - INTERVAL %s and cp_client != 'auto' ",
|
||||
db_utcnow(),
|
||||
db_quoteinterval('3 MINUTE')
|
||||
);
|
||||
|
||||
// expire any expired mail
|
||||
|
||||
@@ -97,26 +103,26 @@ class Cron {
|
||||
|
||||
// Clean expired photos from cache
|
||||
|
||||
$age = get_config('system','active_expire_days', '30');
|
||||
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . ' DAY')
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
if($r) {
|
||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
foreach($r as $rr) {
|
||||
$file = dbunescbin($rr['content']);
|
||||
if(is_file($file)) {
|
||||
@unlink($file);
|
||||
@rmdir(dirname($file));
|
||||
logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . ' DAY')
|
||||
);
|
||||
|
||||
// publish any applicable items that were set to be published in the future
|
||||
// (time travel posts). Restrict to items that have come of age in the last
|
||||
@@ -138,7 +144,7 @@ class Cron {
|
||||
if($z) {
|
||||
xchan_query($z);
|
||||
$sync_item = fetch_post_tags($z);
|
||||
build_sync_packet($sync_item[0]['uid'],
|
||||
Libsync::build_sync_packet($sync_item[0]['uid'],
|
||||
[
|
||||
'item' => [ encode_item($sync_item[0],true) ]
|
||||
]
|
||||
@@ -149,6 +155,11 @@ class Cron {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check if any connections transitioned to zot6 and upgrade the connections to zot6 at this hub if so.
|
||||
require_once('include/connections.php');
|
||||
z6trans_connections();
|
||||
|
||||
require_once('include/attach.php');
|
||||
attach_upgrade();
|
||||
|
||||
@@ -187,7 +198,7 @@ class Cron {
|
||||
if($r) {
|
||||
require_once('include/photo/photo_driver.php');
|
||||
foreach($r as $rr) {
|
||||
$photos = import_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']);
|
||||
$photos = import_xchan_photo($rr['xchan_photo_l'], $rr['xchan_hash'], false, true);
|
||||
$x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
|
||||
where xchan_hash = '%s'",
|
||||
dbesc($photos[0]),
|
||||
@@ -214,7 +225,7 @@ class Cron {
|
||||
$restart = true;
|
||||
$generation = intval($argv[2]);
|
||||
if(! $generation)
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
reload_plugins();
|
||||
|
||||
@@ -44,6 +44,17 @@ class Cron_daily {
|
||||
db_utcnow(), db_quoteinterval('1 YEAR')
|
||||
);
|
||||
|
||||
// expire anonymous sse notification entries once a day
|
||||
|
||||
q("delete from xconfig where xchan like '%s'",
|
||||
dbesc('sse_id.%')
|
||||
);
|
||||
|
||||
// Clean up emdedded content cache
|
||||
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
|
||||
//update statistics in config
|
||||
require_once('include/statistics_fns.php');
|
||||
@@ -86,6 +97,8 @@ class Cron_daily {
|
||||
|
||||
remove_obsolete_hublocs();
|
||||
|
||||
z6_discover();
|
||||
|
||||
call_hooks('cron_daily',datetime_convert());
|
||||
|
||||
set_config('system','last_expire_day',intval(datetime_convert('UTC','UTC','now','d')));
|
||||
|
||||
@@ -13,7 +13,7 @@ class CurlAuth {
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
if($argc != 2)
|
||||
killme();
|
||||
return;
|
||||
|
||||
\App::$session->start();
|
||||
|
||||
@@ -50,6 +50,6 @@ class CurlAuth {
|
||||
|
||||
file_put_contents($c,$x);
|
||||
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\DReport;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/queue_fn.php');
|
||||
|
||||
|
||||
class Deliver {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
@@ -22,72 +18,16 @@ class Deliver {
|
||||
if(! $argv[$x])
|
||||
continue;
|
||||
|
||||
$dresult = null;
|
||||
$r = q("select * from outq where outq_hash = '%s' limit 1",
|
||||
$r = q("select * from outq where outq_hash = '%s'",
|
||||
dbesc($argv[$x])
|
||||
);
|
||||
|
||||
if($r) {
|
||||
|
||||
$notify = json_decode($r[0]['outq_notify'],true);
|
||||
|
||||
// Messages without an outq_msg will need to go via the web, even if it's a
|
||||
// local delivery. This includes conversation requests and refresh packets.
|
||||
|
||||
if(($r[0]['outq_posturl'] === z_root() . '/post') && ($r[0]['outq_msg'])) {
|
||||
logger('deliver: local delivery', LOGGER_DEBUG);
|
||||
|
||||
// local delivery
|
||||
// we should probably batch these and save a few delivery processes
|
||||
|
||||
if($r[0]['outq_msg']) {
|
||||
$m = json_decode($r[0]['outq_msg'],true);
|
||||
if(array_key_exists('message_list',$m)) {
|
||||
foreach($m['message_list'] as $mm) {
|
||||
$msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $mm)))));
|
||||
zot_import($msg,z_root());
|
||||
}
|
||||
}
|
||||
else {
|
||||
$msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $m)))));
|
||||
$dresult = zot_import($msg,z_root());
|
||||
}
|
||||
|
||||
remove_queue_item($r[0]['outq_hash']);
|
||||
|
||||
if($dresult && is_array($dresult)) {
|
||||
|
||||
// delivery reports for local deliveries do not require encryption
|
||||
|
||||
foreach($dresult as $xx) {
|
||||
if(is_array($xx) && array_key_exists('message_id',$xx)) {
|
||||
if(DReport::is_storable($xx)) {
|
||||
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
|
||||
dbesc($xx['message_id']),
|
||||
dbesc($xx['location']),
|
||||
dbesc($xx['recipient']),
|
||||
dbesc(($xx['name']) ? $xx['name'] : EMPTY_STR),
|
||||
dbesc($xx['status']),
|
||||
dbesc(datetime_convert($xx['date'])),
|
||||
dbesc($xx['sender'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q("delete from dreport where dreport_queue = '%s'",
|
||||
dbesc($argv[$x])
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise it's a remote delivery - call queue_deliver() with the $immediate flag
|
||||
|
||||
queue_deliver($r[0],true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/dir_fns.php');
|
||||
require_once('include/queue_fn.php');
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
use Zotlabs\Lib\Queue;
|
||||
|
||||
class Directory {
|
||||
|
||||
@@ -42,7 +41,7 @@ class Directory {
|
||||
|
||||
// this is an in-memory update and we don't need to send a network packet.
|
||||
|
||||
local_dir_update($argv[1],$force);
|
||||
Libzotdir::local_dir_update($argv[1],$force);
|
||||
|
||||
q("update channel set channel_dirdate = '%s' where channel_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
@@ -58,13 +57,16 @@ class Directory {
|
||||
|
||||
// otherwise send the changes upstream
|
||||
|
||||
$directory = find_upstream_directory($dirmode);
|
||||
$url = $directory['url'] . '/post';
|
||||
$directory = Libzotdir::find_upstream_directory($dirmode);
|
||||
|
||||
$url = $directory['url'] . '/zot';
|
||||
|
||||
// ensure the upstream directory is updated
|
||||
|
||||
$packet = zot_build_packet($channel,(($force) ? 'force_refresh' : 'refresh'));
|
||||
$z = zot_zot($url,$packet);
|
||||
|
||||
$packet = Libzot::build_packet($channel,(($force) ? 'force_refresh' : 'refresh'));
|
||||
$z = Libzot::zot($url,$packet,$channel);
|
||||
|
||||
|
||||
// re-queue if unsuccessful
|
||||
|
||||
@@ -76,7 +78,7 @@ class Directory {
|
||||
|
||||
$hash = random_string();
|
||||
|
||||
queue_insert(array(
|
||||
Queue::insert(array(
|
||||
'hash' => $hash,
|
||||
'account_id' => $channel['channel_account_id'],
|
||||
'channel_id' => $channel['channel_id'],
|
||||
|
||||
@@ -8,6 +8,15 @@ class Expire {
|
||||
static public function run($argc,$argv){
|
||||
|
||||
cli_startup();
|
||||
|
||||
$pid = get_config('expire', 'procid', false);
|
||||
if ($pid && (function_exists('posix_kill') ? posix_kill($pid, 0) : true)) {
|
||||
logger('Expire: procedure already run with pid ' . $pid, LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$pid = getmypid();
|
||||
set_config('expire', 'procid', $pid);
|
||||
|
||||
// perform final cleanup on previously delete items
|
||||
|
||||
@@ -32,7 +41,7 @@ class Expire {
|
||||
if (intval(get_config('system', 'optimize_items')))
|
||||
q("optimize table item");
|
||||
|
||||
logger('expire: start', LOGGER_DEBUG);
|
||||
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'));
|
||||
@@ -90,5 +99,7 @@ class Expire {
|
||||
|
||||
logger('Expire: sys: done', LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
del_config('expire', 'procid');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Webfinger;
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
|
||||
// performs zot_finger on $argv[1], which is a hex_encoded webbie/reddress
|
||||
|
||||
@@ -17,17 +19,21 @@ class Gprobe {
|
||||
if(! strpos($url,'@'))
|
||||
return;
|
||||
|
||||
$r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
|
||||
$r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($url)
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
$j = \Zotlabs\Zot\Finger::run($url,null);
|
||||
if($j['success']) {
|
||||
$y = import_xchan($j);
|
||||
$href = Webfinger::zot_url(punify($url));
|
||||
if($href) {
|
||||
$zf = Zotfinger::exec($href, null);
|
||||
}
|
||||
if(is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
|
||||
$xc = Libzot::import_xchan($zf['data']);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
class Importfile {
|
||||
|
||||
static public function run($argc,$argv){
|
||||
@@ -40,7 +42,7 @@ class Importfile {
|
||||
|
||||
$sync = attach_export_data($channel,$hash);
|
||||
if($sync)
|
||||
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
|
||||
|
||||
if($argc)
|
||||
Master::Release($argc,$argv);
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,22 @@ if(array_search( __file__ , get_included_files()) === 0) {
|
||||
class Master {
|
||||
|
||||
static public function Summon($arr) {
|
||||
proc_run('php','Zotlabs/Daemon/Master.php',$arr);
|
||||
$hookinfo = [
|
||||
'argv'=>$arr
|
||||
];
|
||||
|
||||
call_hooks ('daemon_master_summon',$hookinfo);
|
||||
|
||||
$arr = $hookinfo['argv'];
|
||||
$argc = count($arr);
|
||||
|
||||
if ((!is_array($arr) || (count($arr) < 1))) {
|
||||
logger("Summon handled by hook.",LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$phpbin = get_config('system','phpbin','php');
|
||||
proc_run($phpbin,'Zotlabs/Daemon/Master.php',$arr);
|
||||
}
|
||||
|
||||
static public function Release($argc,$argv) {
|
||||
@@ -33,6 +48,7 @@ class Master {
|
||||
$argc = count($argv);
|
||||
|
||||
if ((!is_array($argv) || (count($argv) < 1))) {
|
||||
logger("Release handled by hook.",LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\Queue;
|
||||
|
||||
require_once('include/queue_fn.php');
|
||||
require_once('include/html2plain.php');
|
||||
@@ -15,26 +17,26 @@ require_once('include/bbcode.php');
|
||||
|
||||
/*
|
||||
* This file was at one time responsible for doing all deliveries, but this caused
|
||||
* big problems on shared hosting systems, where the process might get killed by the
|
||||
* hosting provider and nothing would get delivered.
|
||||
* big problems on shared hosting systems, where the process might get killed by the
|
||||
* hosting provider and nothing would get delivered.
|
||||
* It now only delivers one message under certain cases, and invokes a queued
|
||||
* delivery mechanism (include/deliver.php) to deliver individual contacts at
|
||||
* delivery mechanism (include/deliver.php) to deliver individual contacts at
|
||||
* controlled intervals.
|
||||
* This has a much better chance of surviving random processes getting killed
|
||||
* by the hosting provider.
|
||||
* by the hosting provider.
|
||||
*
|
||||
* The basic flow is:
|
||||
* Identify the type of message
|
||||
* Collect any information that needs to be sent
|
||||
* Convert it into a suitable generic format for sending
|
||||
* Figure out who the recipients are and if we need to relay
|
||||
* Figure out who the recipients are and if we need to relay
|
||||
* through a conversation owner
|
||||
* Once we know what recipients are involved, collect a list of
|
||||
* Once we know what recipients are involved, collect a list of
|
||||
* destination sites
|
||||
* Build and store a queue item for each unique site and invoke
|
||||
* a delivery process for each site or a small number of sites (1-3)
|
||||
* and add a slight delay between each delivery invocation if desired (usually)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -44,30 +46,31 @@ require_once('include/bbcode.php');
|
||||
*
|
||||
* where COMMAND is one of the following:
|
||||
*
|
||||
* activity (in diaspora.php, dfrn_confirm.php, profiles.php)
|
||||
* comment-import (in diaspora.php, items.php)
|
||||
* comment-new (in item.php)
|
||||
* drop (in diaspora.php, items.php, photos.php)
|
||||
* edit_post (in item.php)
|
||||
* event (in events.php)
|
||||
* expire (in items.php)
|
||||
* like (in like.php, poke.php)
|
||||
* mail (in message.php)
|
||||
* tag (in photos.php, poke.php, tagger.php)
|
||||
* tgroup (in items.php)
|
||||
* wall-new (in photos.php, item.php)
|
||||
* activity (in diaspora.php, dfrn_confirm.php, profiles.php)
|
||||
* comment-import (in diaspora.php, items.php)
|
||||
* comment-new (in item.php)
|
||||
* drop (in diaspora.php, items.php, photos.php)
|
||||
* edit_post (in item.php)
|
||||
* event (in events.php)
|
||||
* expire (in items.php)
|
||||
* like (in like.php, poke.php)
|
||||
* mail (in message.php)
|
||||
* tag (in photos.php, poke.php, tagger.php)
|
||||
* tgroup (in items.php)
|
||||
* wall-new (in photos.php, item.php)
|
||||
*
|
||||
* and ITEM_ID is the id of the item in the database that needs to be sent to others.
|
||||
*
|
||||
* ZOT
|
||||
* ZOT
|
||||
* permission_create abook_id
|
||||
* permission_accept abook_id
|
||||
* permission_reject abook_id
|
||||
* permission_update abook_id
|
||||
* refresh_all channel_id
|
||||
* purge channel_id xchan_hash
|
||||
* purge_all channel_id
|
||||
* expire channel_id
|
||||
* relay item_id (item was relayed to owner, we will deliver it as owner)
|
||||
* relay item_id (item was relayed to owner, we will deliver it as owner)
|
||||
* single_activity item_id (deliver to a singleton network from the appropriate clone)
|
||||
* single_mail mail_id (deliver to a singleton network from the appropriate clone)
|
||||
* location channel_id
|
||||
@@ -164,7 +167,7 @@ class Notifier {
|
||||
$normal_mode = false;
|
||||
}
|
||||
elseif(in_array($cmd, [ 'permission_update', 'permission_reject', 'permission_accept', 'permission_create' ])) {
|
||||
// Get the (single) recipient
|
||||
// Get the (single) recipient
|
||||
$r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0",
|
||||
intval($item_id)
|
||||
);
|
||||
@@ -173,7 +176,7 @@ class Notifier {
|
||||
// Get the sender
|
||||
$channel = channelx_by_n($uid);
|
||||
if($channel) {
|
||||
$perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
|
||||
$perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
|
||||
|
||||
if($cmd === 'permission_create')
|
||||
call_hooks('permissions_create',$perm_update);
|
||||
@@ -189,7 +192,7 @@ class Notifier {
|
||||
$deliveries[] = $perm_update['deliveries'];
|
||||
do_delivery($deliveries);
|
||||
}
|
||||
return;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$recipients[] = $r[0]['abook_xchan'];
|
||||
@@ -233,31 +236,46 @@ class Notifier {
|
||||
}
|
||||
}
|
||||
|
||||
$encoded_item = array('locations' => zot_encode_locations($channel),'type' => 'location', 'encoding' => 'zot');
|
||||
$encoded_item = array('locations' => Libzot::encode_locations($channel),'type' => 'location', 'encoding' => 'zot');
|
||||
$target_item = array('aid' => $channel['channel_account_id'],'uid' => $channel['channel_id']);
|
||||
$private = false;
|
||||
$packet_type = 'location';
|
||||
$location = true;
|
||||
}
|
||||
elseif($cmd === 'purge') {
|
||||
$xchan = $argv[3];
|
||||
logger('notifier: purge: ' . $item_id . ' => ' . $xchan);
|
||||
if (! $xchan) {
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = channelx_by_n($item_id);
|
||||
$recipients[] = $xchan;
|
||||
$private = true;
|
||||
$packet_type = 'purge';
|
||||
$packet_recips[] = ['hash' => $xchan];
|
||||
}
|
||||
elseif($cmd === 'purge_all') {
|
||||
|
||||
logger('notifier: purge_all: ' . $item_id);
|
||||
$s = q("select * from channel where channel_id = %d limit 1",
|
||||
intval($item_id)
|
||||
);
|
||||
if($s)
|
||||
$channel = $s[0];
|
||||
$uid = $item_id;
|
||||
$recipients = array();
|
||||
$channel = channelx_by_n($item_id);
|
||||
|
||||
$recipients = [];
|
||||
$r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 0",
|
||||
intval($item_id)
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
$recipients[] = $rr['abook_xchan'];
|
||||
}
|
||||
if (! $r) {
|
||||
return;
|
||||
}
|
||||
foreach ($r as $rr) {
|
||||
$recipients[] = $rr['abook_xchan'];
|
||||
$packet_recips[] = ['hash' => $rr['abook_xchan']];
|
||||
}
|
||||
|
||||
$private = false;
|
||||
$packet_type = 'purge';
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -275,8 +293,14 @@ class Notifier {
|
||||
xchan_query($r);
|
||||
|
||||
$r = fetch_post_tags($r);
|
||||
|
||||
|
||||
$target_item = $r[0];
|
||||
|
||||
if(in_array($target_item['author']['xchan_network'], ['rss', 'anon'])) {
|
||||
logger('notifier: target item author is not a fetchable actor', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$deleted_item = false;
|
||||
|
||||
if(intval($target_item['item_deleted'])) {
|
||||
@@ -285,14 +309,27 @@ class Notifier {
|
||||
}
|
||||
|
||||
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
|
||||
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
|
||||
return;
|
||||
$hookinfo=[
|
||||
'targetitem'=>$target_item,
|
||||
'deliver'=>false
|
||||
];
|
||||
if (intval($target_item['item_type'] == ITEM_TYPE_CUSTOM)) {
|
||||
call_hooks('customitem_deliver',$hookinfo);
|
||||
}
|
||||
|
||||
if (!$hookinfo['deliver']) {
|
||||
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$target_item = $hookinfo['targetitem'];
|
||||
|
||||
}
|
||||
|
||||
// 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_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;
|
||||
@@ -335,7 +372,7 @@ class Notifier {
|
||||
|
||||
xchan_query($r);
|
||||
$r = fetch_post_tags($r);
|
||||
|
||||
|
||||
$parent_item = $r[0];
|
||||
$top_level_post = false;
|
||||
}
|
||||
@@ -347,23 +384,32 @@ class Notifier {
|
||||
|
||||
$encoded_item = encode_item($target_item);
|
||||
|
||||
// activitystreams version
|
||||
$m = get_iconfig($target_item,'activitystreams','signed_data');
|
||||
// Re-use existing signature unless the activity type changed to a Tombstone, which won't verify.
|
||||
$m = ((intval($target_item['item_deleted'])) ? '' : get_iconfig($target_item,'activitystreams','signed_data'));
|
||||
|
||||
if($m) {
|
||||
$activity = json_decode($m,true);
|
||||
}
|
||||
else {
|
||||
$activity = \Zotlabs\Lib\Activity::encode_activity($target_item);
|
||||
}
|
||||
$activity = array_merge(['@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1',
|
||||
z_root() . ZOT_APSCHEMA_REV
|
||||
]], Activity::encode_activity($target_item)
|
||||
);
|
||||
}
|
||||
|
||||
logger('target_item: ' . print_r($target_item,true), LOGGER_DEBUG);
|
||||
logger('encoded: ' . print_r($activity,true), LOGGER_DEBUG);
|
||||
|
||||
// Send comments to the owner to re-deliver to everybody in the conversation
|
||||
// We only do this if the item in question originated on this site. This prevents looping.
|
||||
// To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
|
||||
// Relaying should never be initiated on a post that arrived from elsewhere.
|
||||
// Relaying should never be initiated on a post that arrived from elsewhere.
|
||||
|
||||
// We should normally be able to rely on ITEM_ORIGIN, but start_delivery_chain() incorrectly set this
|
||||
// flag on comments for an extended period. So we'll also call comment_local_origin() which looks at
|
||||
// the hostname in the message_id and provides a second (fallback) opinion.
|
||||
// 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)) ? true : false);
|
||||
|
||||
@@ -380,9 +426,9 @@ class Notifier {
|
||||
// tag_deliver'd post which needs to be sent back to the original author
|
||||
|
||||
if(($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) {
|
||||
logger('notifier: uplink');
|
||||
logger('notifier: uplink');
|
||||
$uplink = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
|
||||
logger('notifier: followup relay', LOGGER_DEBUG);
|
||||
@@ -399,8 +445,8 @@ class Notifier {
|
||||
logger('notifier: owner relay');
|
||||
$upstream = false;
|
||||
// if our parent is a tag_delivery recipient, uplink to the original author causing
|
||||
// a delivery fork.
|
||||
|
||||
// a delivery fork.
|
||||
|
||||
if(($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) {
|
||||
// don't uplink a relayed post to the relay owner
|
||||
if($parent_item['source_xchan'] !== $parent_item['owner_xchan']) {
|
||||
@@ -416,7 +462,7 @@ class Notifier {
|
||||
if ($top_level_post) {
|
||||
// remove clones who will receive the post via sync
|
||||
$recipients = array_diff($recipients, [ $target_item['owner_xchan'] ]);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME add any additional recipients such as mentions, etc.
|
||||
|
||||
@@ -430,7 +476,7 @@ class Notifier {
|
||||
}
|
||||
}
|
||||
|
||||
$walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false);
|
||||
$walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false);
|
||||
|
||||
// Generic delivery section, we have an encoded item and recipients
|
||||
// Now start the delivery process
|
||||
@@ -452,15 +498,14 @@ class Notifier {
|
||||
|
||||
$env_recips = (($private) ? array() : null);
|
||||
|
||||
$details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . protect_sprintf(implode(',',$recipients)) . ")");
|
||||
|
||||
$details = q("select xchan_hash, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . protect_sprintf(implode(',',$recipients)) . ")");
|
||||
|
||||
$recip_list = array();
|
||||
|
||||
if($details) {
|
||||
foreach($details as $d) {
|
||||
|
||||
$recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
|
||||
$recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
|
||||
if($private) {
|
||||
$env_recips[] = [
|
||||
'guid' => $d['xchan_guid'],
|
||||
@@ -512,27 +557,49 @@ class Notifier {
|
||||
// shouldn't happen
|
||||
logger('notifier: private message with no envelope recipients.' . print_r($argv,true), LOGGER_NORMAL, LOG_NOTICE);
|
||||
}
|
||||
|
||||
|
||||
logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list,true), LOGGER_DEBUG);
|
||||
|
||||
|
||||
|
||||
// Now we have collected recipients (except for external mentions, FIXME)
|
||||
// Let's reduce this to a set of hubs; checking that the site is not dead.
|
||||
|
||||
$r = q("select hubloc.*, site.site_crypto, site.site_flags from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ")
|
||||
and hubloc_error = 0 and hubloc_deleted = 0 and ( site_dead = 0 OR site_dead is null ) "
|
||||
);
|
||||
|
||||
$hubs = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc left join site on site_url = hubloc_url
|
||||
where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ")
|
||||
and hubloc_error = 0 and hubloc_deleted = 0"
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
// 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
|
||||
|
||||
if (! $private) {
|
||||
$found_localhost = false;
|
||||
if ($hubs) {
|
||||
foreach ($hubs as $h) {
|
||||
if ($h['hubloc_url'] === z_root()) {
|
||||
$found_localhost = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! $found_localhost) {
|
||||
$localhub = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc
|
||||
left join site on site_url = hubloc_url where hubloc_id_url = '%s' and hubloc_error = 0 and hubloc_deleted = 0",
|
||||
dbesc(z_root() . '/channel/sys')
|
||||
);
|
||||
if ($localhub) {
|
||||
$hubs = array_merge($hubs, $localhub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(! $hubs) {
|
||||
logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
|
||||
return;
|
||||
}
|
||||
|
||||
$hubs = $r;
|
||||
|
||||
/**
|
||||
* Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey,
|
||||
* Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey,
|
||||
* since it may have been a re-install which has not yet been detected and pruned.
|
||||
* For other networks which don't have or require sitekeys, we'll have to use the URL
|
||||
*/
|
||||
@@ -543,9 +610,15 @@ class Notifier {
|
||||
$keys = []; // array of keys to check uniquness for zot hubs
|
||||
$urls = []; // array of urls to check uniqueness of hubs from other networks
|
||||
$hub_env = []; // per-hub envelope so we don't broadcast the entire envelope to all
|
||||
$dead = []; // known dead hubs - report them as undeliverable
|
||||
|
||||
foreach($hubs as $hub) {
|
||||
|
||||
if (intval($hub['site_dead'])) {
|
||||
$dead[] = $hub;
|
||||
continue;
|
||||
}
|
||||
|
||||
if($env_recips) {
|
||||
foreach($env_recips as $er) {
|
||||
if($hub['hubloc_hash'] === $er['hash']) {
|
||||
@@ -556,7 +629,7 @@ class Notifier {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if($hub['hubloc_network'] == 'zot') {
|
||||
if(! in_array($hub['hubloc_sitekey'],$keys)) {
|
||||
@@ -567,9 +640,16 @@ class Notifier {
|
||||
}
|
||||
else {
|
||||
if(! in_array($hub['hubloc_url'],$urls)) {
|
||||
$hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
|
||||
$dhubs[] = $hub;
|
||||
$urls[] = $hub['hubloc_url'];
|
||||
if($hub['hubloc_url'] === z_root()) {
|
||||
//deliver to local hub first
|
||||
array_unshift($hublist, $hub['hubloc_host'] . ' ' . $hub['hubloc_network']);
|
||||
array_unshift($dhubs, $hub);
|
||||
}
|
||||
else {
|
||||
$hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
|
||||
$dhubs[] = $hub;
|
||||
}
|
||||
$urls[] = $hub['hubloc_url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -617,7 +697,7 @@ class Notifier {
|
||||
}
|
||||
|
||||
// singleton deliveries by definition 'not got zot'.
|
||||
// Single deliveries are other federated networks (plugins) and we're essentially
|
||||
// Single deliveries are other federated networks (plugins) and we're essentially
|
||||
// delivering only to those that have this site url in their abook_instance
|
||||
// and only from within a sync operation. This means if you post from a clone,
|
||||
// and a connection is connected to one of your other clones; assuming that hub
|
||||
@@ -634,8 +714,8 @@ class Notifier {
|
||||
}
|
||||
|
||||
// Do not change this to a uuid as long as we have traditional zot servers
|
||||
// in the loop. The signature verification step can't handle dashes in the
|
||||
// hashes.
|
||||
// in the loop. The signature verification step can't handle dashes in the
|
||||
// hashes.
|
||||
|
||||
$hash = random_string(48);
|
||||
|
||||
@@ -662,15 +742,17 @@ class Notifier {
|
||||
}
|
||||
|
||||
if($packet) {
|
||||
queue_insert(array(
|
||||
'hash' => $hash,
|
||||
'account_id' => $channel['channel_account_id'],
|
||||
'channel_id' => $channel['channel_id'],
|
||||
'posturl' => $hub['hubloc_callback'],
|
||||
'driver' => $hub['hubloc_network'],
|
||||
'notify' => $packet,
|
||||
'msg' => (($pmsg) ? json_encode($pmsg) : '')
|
||||
));
|
||||
Queue::insert(
|
||||
[
|
||||
'hash' => $hash,
|
||||
'account_id' => $channel['channel_account_id'],
|
||||
'channel_id' => $channel['channel_id'],
|
||||
'posturl' => $hub['hubloc_callback'],
|
||||
'driver' => $hub['hubloc_network'],
|
||||
'notify' => $packet,
|
||||
'msg' => (($pmsg) ? json_encode($pmsg) : '')
|
||||
]
|
||||
);
|
||||
}
|
||||
else {
|
||||
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
|
||||
@@ -684,13 +766,13 @@ class Notifier {
|
||||
}
|
||||
}
|
||||
|
||||
$packet_type = (($upstream || $uplink) ? 'response' : 'activity');
|
||||
$packet_type = (($upstream || $uplink) ? 'response' : 'activity');
|
||||
|
||||
// block zot private reshares from zot6, as this could cause a number of privacy issues
|
||||
// due to parenting differences between the reshare implementations. In zot a reshare is
|
||||
// a standalone parent activity and in zot6 it is a followup/child of the original activity.
|
||||
// For public reshares, some comments to the reshare on the zot fork will not make it to zot6
|
||||
// due to these different message models. This cannot be prevented at this time.
|
||||
// due to these different message models. This cannot be prevented at this time.
|
||||
|
||||
if($packet_type === 'activity' && $activity['type'] === 'Announce' && intval($target_item['item_private'])) {
|
||||
continue;
|
||||
@@ -700,7 +782,7 @@ class Notifier {
|
||||
}
|
||||
else {
|
||||
// currently zot6 delivery is only performed on normal items and not sync items or mail or anything else
|
||||
// Eventually we will do this for all deliveries, but for now ensure this is precisely what we are dealing
|
||||
// Eventually we will do this for all deliveries, but for now ensure this is precisely what we are dealing
|
||||
// with before switching to zot6 as the primary zot6 handler checks for the existence of a message delivery report
|
||||
// to trigger dequeue'ing
|
||||
|
||||
@@ -712,9 +794,26 @@ class Notifier {
|
||||
$packet = zot_build_packet($channel,'notify',$env, (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queue_insert(
|
||||
|
||||
// remove this after most hubs have updated to version 5.0
|
||||
if(stripos($hub['site_project'], 'hubzilla') !== false && version_compare($hub['site_version'], '4.7.3', '<=')) {
|
||||
if($encoded_item['type'] === 'mail') {
|
||||
$encoded_item['from']['network'] = 'zot';
|
||||
$encoded_item['from']['guid_sig'] = str_replace('sha256.', '', $encoded_item['from']['guid_sig']);
|
||||
}
|
||||
else {
|
||||
$encoded_item['owner']['network'] = 'zot';
|
||||
$encoded_item['owner']['guid_sig'] = str_replace('sha256.', '', $encoded_item['owner']['guid_sig']);
|
||||
if(strpos($encoded_item['author']['url'], z_root()) === 0) {
|
||||
$encoded_item['author']['network'] = 'zot';
|
||||
$encoded_item['author']['guid_sig'] = str_replace('sha256.', '', $encoded_item['author']['guid_sig']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Queue::insert(
|
||||
[
|
||||
'hash' => $hash,
|
||||
'account_id' => $target_item['aid'],
|
||||
@@ -740,9 +839,9 @@ class Notifier {
|
||||
}
|
||||
}
|
||||
|
||||
$deliveries[] = $hash;
|
||||
$deliveries[] = $hash;
|
||||
}
|
||||
|
||||
|
||||
if($normal_mode) {
|
||||
$x = q("select * from hook where hook = 'notifier_normal'");
|
||||
if($x) {
|
||||
@@ -755,6 +854,24 @@ class Notifier {
|
||||
|
||||
logger('notifier: basic loop complete.', LOGGER_DEBUG);
|
||||
|
||||
if ($dead) {
|
||||
foreach ($dead as $deceased) {
|
||||
if (is_array($target_item) && (! $target_item['item_deleted']) && (! get_config('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']),
|
||||
dbesc($deceased['hubloc_host']),
|
||||
dbesc($deceased['hubloc_host']),
|
||||
dbesc($deceased['hubloc_host']),
|
||||
dbesc('undeliverable/unresponsive site'),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($channel['channel_hash']),
|
||||
dbesc(random_string(48))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call_hooks('notifier_end',$target_item);
|
||||
|
||||
logger('notifer: complete.');
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/dir_fns.php');
|
||||
|
||||
@@ -11,7 +13,7 @@ class Onedirsync {
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
logger('onedirsync: start ' . intval($argv[1]));
|
||||
|
||||
|
||||
if(($argc > 1) && (intval($argv[1])))
|
||||
$update_id = intval($argv[1]);
|
||||
|
||||
@@ -19,7 +21,7 @@ class Onedirsync {
|
||||
logger('onedirsync: no update');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$r = q("select * from updates where ud_id = %d limit 1",
|
||||
intval($update_id)
|
||||
);
|
||||
@@ -50,10 +52,13 @@ class Onedirsync {
|
||||
|
||||
// ignore doing an update if this ud_addr refers to a known dead hubloc
|
||||
|
||||
$h = q("select * from hubloc where hubloc_addr = '%s' limit 1",
|
||||
$h = q("select * from hubloc where hubloc_addr = '%s'",
|
||||
dbesc($r[0]['ud_addr'])
|
||||
);
|
||||
if(($h) && ($h[0]['hubloc_status'] & HUBLOC_OFFLINE)) {
|
||||
|
||||
$h = Libzot::zot_record_preferred($h);
|
||||
|
||||
if(($h) && ($h['hubloc_status'] & HUBLOC_OFFLINE)) {
|
||||
$y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ",
|
||||
intval(UPDATE_FLAGS_UPDATED),
|
||||
dbesc($r[0]['ud_addr']),
|
||||
@@ -63,13 +68,13 @@ class Onedirsync {
|
||||
return;
|
||||
}
|
||||
|
||||
// we might have to pull this out some day, but for now update_directory_entry()
|
||||
// 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[0]['hubloc_network'] !== 'zot')
|
||||
if($h && ! in_array($h['hubloc_network'], ['zot6', 'zot']))
|
||||
return;
|
||||
|
||||
update_directory_entry($r[0]);
|
||||
update_directory_entry($r[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/socgraph.php');
|
||||
|
||||
@@ -61,11 +63,13 @@ class Onepoll {
|
||||
|
||||
if($contact['xchan_network'] === 'rss') {
|
||||
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
|
||||
handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
$alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
||||
if ($alive) {
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -74,7 +78,11 @@ class Onepoll {
|
||||
|
||||
// update permissions
|
||||
|
||||
$x = zot_refresh($contact,$importer);
|
||||
if($contact['xchan_network'] === 'zot6')
|
||||
$x = Libzot::refresh($contact,$importer);
|
||||
|
||||
if($contact['xchan_network'] === 'zot')
|
||||
$x = zot_refresh($contact,$importer);
|
||||
|
||||
$responded = false;
|
||||
$updated = datetime_convert();
|
||||
|
||||
@@ -47,7 +47,7 @@ class Poller {
|
||||
$restart = true;
|
||||
$generation = intval($argv[2]);
|
||||
if(! $generation)
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
if(($argc > 1) && intval($argv[1])) {
|
||||
@@ -199,6 +199,7 @@ class Poller {
|
||||
set_config('system','lastpoll',datetime_convert());
|
||||
|
||||
//All done - clear the lockfile
|
||||
|
||||
@unlink($lockfile);
|
||||
|
||||
return;
|
||||
|
||||
@@ -10,6 +10,11 @@ class Ratenotif {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
|
||||
// Deprecated
|
||||
return;
|
||||
|
||||
|
||||
require_once("datetime.php");
|
||||
require_once('include/items.php');
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Identity\BasicId;
|
||||
namespace Zotlabs\Identity;
|
||||
|
||||
class BasicId {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Zotlabs\Identity\ProfilePhoto;
|
||||
namespace Zotlabs\Identity;
|
||||
|
||||
class ProfilePhoto {
|
||||
|
||||
|
||||
411
Zotlabs/Lib/AccessList.php
Normal file
411
Zotlabs/Lib/AccessList.php
Normal file
@@ -0,0 +1,411 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
|
||||
class AccessList {
|
||||
|
||||
static function add($uid,$name,$public = 0) {
|
||||
|
||||
$ret = false;
|
||||
if ($uid && $name) {
|
||||
$r = self::byname($uid,$name); // check for dups
|
||||
if ($r !== false) {
|
||||
|
||||
// This could be a problem.
|
||||
// Let's assume we've just created a list which we once deleted
|
||||
// all the old members are gone, but the list remains so we don't break any security
|
||||
// access lists. What we're doing here is reviving the dead list, but old content which
|
||||
// was restricted to this list may now be seen by the new list members.
|
||||
|
||||
$z = q("SELECT * FROM pgrp WHERE id = %d LIMIT 1",
|
||||
intval($r)
|
||||
);
|
||||
if(($z) && $z[0]['deleted']) {
|
||||
q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id']));
|
||||
notice( t('A deleted list with this name was revived. Existing item permissions <strong>may</strong> apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$hash = new_uuid();
|
||||
|
||||
$r = q("INSERT INTO pgrp ( hash, uid, visible, gname )
|
||||
VALUES( '%s', %d, %d, '%s' ) ",
|
||||
dbesc($hash),
|
||||
intval($uid),
|
||||
intval($public),
|
||||
dbesc($name)
|
||||
);
|
||||
$ret = $r;
|
||||
}
|
||||
|
||||
Libsync::build_sync_packet($uid,null,true);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
static function remove($uid,$name) {
|
||||
$ret = false;
|
||||
if ($uid && $name) {
|
||||
$r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
|
||||
intval($uid),
|
||||
dbesc($name)
|
||||
);
|
||||
if ($r) {
|
||||
$group_id = $r[0]['id'];
|
||||
$group_hash = $r[0]['hash'];
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove group from default posting lists
|
||||
$r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1",
|
||||
intval($uid)
|
||||
);
|
||||
if ($r) {
|
||||
$user_info = array_shift($r);
|
||||
$change = false;
|
||||
|
||||
if ($user_info['channel_default_group'] == $group_hash) {
|
||||
$user_info['channel_default_group'] = '';
|
||||
$change = true;
|
||||
}
|
||||
if (strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) {
|
||||
$user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']);
|
||||
$change = true;
|
||||
}
|
||||
if (strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) {
|
||||
$user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']);
|
||||
$change = true;
|
||||
}
|
||||
|
||||
if ($change) {
|
||||
q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s'
|
||||
WHERE channel_id = %d",
|
||||
intval($user_info['channel_default_group']),
|
||||
dbesc($user_info['channel_allow_gid']),
|
||||
dbesc($user_info['channel_deny_gid']),
|
||||
intval($uid)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// remove all members
|
||||
$r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ",
|
||||
intval($uid),
|
||||
intval($group_id)
|
||||
);
|
||||
|
||||
// remove group
|
||||
$r = q("UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'",
|
||||
intval($uid),
|
||||
dbesc($name)
|
||||
);
|
||||
|
||||
$ret = $r;
|
||||
|
||||
}
|
||||
|
||||
Libsync::build_sync_packet($uid,null,true);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// returns the integer id of an access group owned by $uid and named $name
|
||||
// or false.
|
||||
|
||||
static function byname($uid,$name) {
|
||||
if (! ($uid && $name)) {
|
||||
return false;
|
||||
}
|
||||
$r = q("SELECT id FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
|
||||
intval($uid),
|
||||
dbesc($name)
|
||||
);
|
||||
if ($r) {
|
||||
return $r[0]['id'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function by_id($uid,$id) {
|
||||
if (! ($uid && $id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$r = q("SELECT * FROM pgrp WHERE uid = %d AND id = %d and deleted = 0",
|
||||
intval($uid),
|
||||
intval($id)
|
||||
);
|
||||
if ($r) {
|
||||
return array_shift($r);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static function rec_byhash($uid,$hash) {
|
||||
if (! ( $uid && $hash)) {
|
||||
return false;
|
||||
}
|
||||
$r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1",
|
||||
intval($uid),
|
||||
dbesc($hash)
|
||||
);
|
||||
if ($r) {
|
||||
return array_shift($r);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static function member_remove($uid,$name,$member) {
|
||||
$gid = self::byname($uid,$name);
|
||||
if (! $gid) {
|
||||
return false;
|
||||
}
|
||||
if (! ($uid && $gid && $member)) {
|
||||
return false;
|
||||
}
|
||||
$r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ",
|
||||
intval($uid),
|
||||
intval($gid),
|
||||
dbesc($member)
|
||||
);
|
||||
|
||||
Libsync::build_sync_packet($uid,null,true);
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
|
||||
static function member_add($uid,$name,$member,$gid = 0) {
|
||||
if (! $gid) {
|
||||
$gid = self::byname($uid,$name);
|
||||
}
|
||||
if (! ($gid && $uid && $member)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1",
|
||||
intval($uid),
|
||||
intval($gid),
|
||||
dbesc($member)
|
||||
);
|
||||
if ($r) {
|
||||
return true; // You might question this, but
|
||||
// we indicate success because the group member was in fact created
|
||||
// -- It was just created at another time
|
||||
}
|
||||
else {
|
||||
$r = q("INSERT INTO pgrp_member (uid, gid, xchan)
|
||||
VALUES( %d, %d, '%s' ) ",
|
||||
intval($uid),
|
||||
intval($gid),
|
||||
dbesc($member)
|
||||
);
|
||||
}
|
||||
Libsync::build_sync_packet($uid,null,true);
|
||||
return $r;
|
||||
}
|
||||
|
||||
|
||||
static function members($uid, $gid) {
|
||||
$ret = [];
|
||||
if (intval($gid)) {
|
||||
$r = q("SELECT * FROM pgrp_member
|
||||
LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
|
||||
WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ",
|
||||
intval($gid),
|
||||
intval($uid),
|
||||
intval($uid)
|
||||
);
|
||||
if ($r) {
|
||||
$ret = $r;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
static function members_xchan($uid,$gid) {
|
||||
$ret = [];
|
||||
if (intval($gid)) {
|
||||
$r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d",
|
||||
intval($gid),
|
||||
intval($uid)
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rv) {
|
||||
$ret[] = $rv['xchan'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
static function members_profile_xchan($uid,$gid) {
|
||||
$ret = [];
|
||||
if (intval($gid)) {
|
||||
$r = q("SELECT abook_xchan as xchan from abook left join profile on abook_profile = profile_guid where profile.id = %d and profile.uid = %d",
|
||||
intval($gid),
|
||||
intval($uid)
|
||||
);
|
||||
if ($r) {
|
||||
foreach($r as $rv) {
|
||||
$ret[] = $rv['xchan'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static function select($uid,$group = '') {
|
||||
|
||||
$grps = [];
|
||||
|
||||
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
|
||||
intval($uid)
|
||||
);
|
||||
$grps[] = [ 'name' => '', 'hash' => '0', 'selected' => '' ];
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$grps[] = [ 'name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '') ];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return replace_macros(get_markup_template('group_selection.tpl'), [
|
||||
'$label' => t('Add new connections to this access list'),
|
||||
'$groups' => $grps
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
static function widget($every="connections",$each="lists",$edit = false, $group_id = 0, $cid = '',$mode = 1) {
|
||||
|
||||
$o = '';
|
||||
|
||||
$groups = [];
|
||||
|
||||
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
|
||||
intval($_SESSION['uid'])
|
||||
);
|
||||
$member_of = [];
|
||||
if ($cid) {
|
||||
$member_of = self::containing(local_channel(),$cid);
|
||||
}
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$selected = (($group_id == $rr['id']) ? ' group-selected' : '');
|
||||
|
||||
if ($edit) {
|
||||
$groupedit = [ 'href' => "lists/".$rr['id'], 'title' => t('edit') ];
|
||||
}
|
||||
else {
|
||||
$groupedit = null;
|
||||
}
|
||||
|
||||
$groups[] = [
|
||||
'id' => $rr['id'],
|
||||
'enc_cid' => base64url_encode($cid),
|
||||
'cid' => $cid,
|
||||
'text' => $rr['gname'],
|
||||
'selected' => $selected,
|
||||
'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''),
|
||||
'edit' => $groupedit,
|
||||
'ismember' => in_array($rr['id'],$member_of),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return replace_macros(get_markup_template('group_side.tpl'), [
|
||||
'$title' => t('Lists'),
|
||||
'$edittext' => t('Edit list'),
|
||||
'$createtext' => t('Create new list'),
|
||||
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''),
|
||||
'$groups' => $groups,
|
||||
'$add' => t('add'),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static function expand($g) {
|
||||
if (! (is_array($g) && count($g))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$ret = [];
|
||||
$x = [];
|
||||
|
||||
// private profile linked virtual groups
|
||||
|
||||
foreach ($g as $gv) {
|
||||
if (substr($gv,0,3) === 'vp.') {
|
||||
$profile_hash = substr($gv,3);
|
||||
if ($profile_hash) {
|
||||
$r = q("select abook_xchan from abook where abook_profile = '%s'",
|
||||
dbesc($profile_hash)
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rv) {
|
||||
$ret[] = $rv['abook_xchan'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$x[] = $gv;
|
||||
}
|
||||
}
|
||||
|
||||
if ($x) {
|
||||
stringify_array_elms($x,true);
|
||||
$groups = implode(',', $x);
|
||||
if ($groups) {
|
||||
$r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))");
|
||||
if ($r) {
|
||||
foreach ($r as $rv) {
|
||||
$ret[] = $rv['xchan'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
static function member_of($c) {
|
||||
$r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id
|
||||
WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ",
|
||||
dbesc($c)
|
||||
);
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
static function containing($uid,$c) {
|
||||
|
||||
$r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ",
|
||||
intval($uid),
|
||||
dbesc($c)
|
||||
);
|
||||
|
||||
$ret = [];
|
||||
if ($r) {
|
||||
foreach ($r as $rv)
|
||||
$ret[] = $rv['gid'];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,13 @@ class ActivityStreams {
|
||||
$this->actor = $this->get_actor('attributedTo',$this->obj);
|
||||
}
|
||||
}
|
||||
|
||||
// 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']);
|
||||
}
|
||||
|
||||
if($this->obj && is_array($this->obj) && $this->obj['actor'])
|
||||
$this->obj['actor'] = $this->get_actor('actor',$this->obj);
|
||||
if($this->tgt && is_array($this->tgt) && $this->tgt['actor'])
|
||||
@@ -140,15 +146,20 @@ class ActivityStreams {
|
||||
*/
|
||||
function collect_recips($base = '', $namespace = '') {
|
||||
$x = [];
|
||||
|
||||
$fields = [ 'to', 'cc', 'bto', 'bcc', 'audience'];
|
||||
foreach($fields as $f) {
|
||||
$y = $this->get_compound_property($f, $base, $namespace);
|
||||
if($y) {
|
||||
$x = array_merge($x, $y);
|
||||
if(! is_array($this->raw_recips))
|
||||
if (! is_array($this->raw_recips)) {
|
||||
$this->raw_recips = [];
|
||||
}
|
||||
|
||||
$this->raw_recips[$f] = $x;
|
||||
if (! is_array($y)) {
|
||||
$y = [ $y ];
|
||||
}
|
||||
$this->raw_recips[$f] = $y;
|
||||
$x = array_merge($x, $y);
|
||||
}
|
||||
}
|
||||
// not yet ready for prime time
|
||||
@@ -263,12 +274,19 @@ class ActivityStreams {
|
||||
return self::fetch($url);
|
||||
}
|
||||
|
||||
static function fetch($url,$channel = null) {
|
||||
return Activity::fetch($url,$channel);
|
||||
static function fetch($url, $channel = null) {
|
||||
return Activity::fetch($url, $channel);
|
||||
}
|
||||
|
||||
static function is_an_actor($s) {
|
||||
return(in_array($s,[ 'Application','Group','Organization','Person','Service' ]));
|
||||
return (in_array($s, [ 'Application','Group','Organization','Person','Service' ]));
|
||||
}
|
||||
|
||||
static function is_response_activity($s) {
|
||||
if (! $s) {
|
||||
return false;
|
||||
}
|
||||
return (in_array($s, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact' ]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,7 +337,10 @@ class ActivityStreams {
|
||||
function get_compound_property($property, $base = '', $namespace = '', $first = false) {
|
||||
$x = $this->get_property_obj($property, $base, $namespace);
|
||||
if($this->is_url($x)) {
|
||||
$x = $this->fetch_property($x);
|
||||
$y = $this->fetch_property($x);
|
||||
if (is_array($y)) {
|
||||
$x = $y;
|
||||
}
|
||||
}
|
||||
|
||||
// verify and unpack JSalmon signature if present
|
||||
@@ -388,7 +409,6 @@ class ActivityStreams {
|
||||
return $x;
|
||||
}
|
||||
|
||||
|
||||
static function is_as_request() {
|
||||
|
||||
$x = getBestSupportedMimeType([
|
||||
@@ -401,5 +421,4 @@ class ActivityStreams {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
require_once('include/plugin.php');
|
||||
require_once('include/channel.php');
|
||||
|
||||
@@ -70,11 +72,10 @@ class Apps {
|
||||
'Channel Home',
|
||||
'View Profile',
|
||||
'Photos',
|
||||
'Events',
|
||||
'Calendar',
|
||||
'Directory',
|
||||
'Search',
|
||||
'Help',
|
||||
'Mail',
|
||||
'Profile Photo'
|
||||
]);
|
||||
|
||||
@@ -328,6 +329,7 @@ class Apps {
|
||||
'Bookmarks' => t('Bookmarks'),
|
||||
'Chatrooms' => t('Chatrooms'),
|
||||
'Content Filter' => t('Content Filter'),
|
||||
'Content Import' => t('Content Import'),
|
||||
'Connections' => t('Connections'),
|
||||
'Remote Diagnostics' => t('Remote Diagnostics'),
|
||||
'Suggest Channels' => t('Suggest Channels'),
|
||||
@@ -341,7 +343,7 @@ class Apps {
|
||||
'Channel Home' => t('Channel Home'),
|
||||
'View Profile' => t('View Profile'),
|
||||
'Photos' => t('Photos'),
|
||||
'Events' => t('Events'),
|
||||
'Calendar' => t('Calendar'),
|
||||
'Directory' => t('Directory'),
|
||||
'Help' => t('Help'),
|
||||
'Mail' => t('Mail'),
|
||||
@@ -362,7 +364,6 @@ class Apps {
|
||||
'Privacy Groups' => t('Privacy Groups'),
|
||||
'Notifications' => t('Notifications'),
|
||||
'Order Apps' => t('Order Apps'),
|
||||
'CalDAV' => t('CalDAV'),
|
||||
'CardDAV' => t('CardDAV'),
|
||||
'Channel Sources' => t('Channel Sources'),
|
||||
'Guest Access' => t('Guest Access'),
|
||||
@@ -371,7 +372,6 @@ class Apps {
|
||||
'OAuth2 Apps Manager' => t('OAuth2 Apps Manager'),
|
||||
'PDL Editor' => t('PDL Editor'),
|
||||
'Permission Categories' => t('Permission Categories'),
|
||||
'Premium Channel' => t('Premium Channel'),
|
||||
'Public Stream' => t('Public Stream'),
|
||||
'My Chatrooms' => t('My Chatrooms'),
|
||||
'Channel Export' => t('Channel Export')
|
||||
@@ -564,7 +564,8 @@ class Apps {
|
||||
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
|
||||
'$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
|
||||
'$navapps' => (($mode == 'nav') ? true : false),
|
||||
'$order' => (($mode == 'nav-order') ? true : false),
|
||||
'$order' => (($mode === 'nav-order' || $mode === 'nav-order-pinned') ? true : false),
|
||||
'$mode' => $mode,
|
||||
'$add' => t('Add to app-tray'),
|
||||
'$remove' => t('Remove from app-tray'),
|
||||
'$add_nav' => t('Pin to navbar'),
|
||||
@@ -604,7 +605,7 @@ class Apps {
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($r[0]['id'])
|
||||
);
|
||||
build_sync_packet($uid,array('app' => $r[0]));
|
||||
Libsync::build_sync_packet($uid,array('app' => $r[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -670,7 +671,7 @@ class Apps {
|
||||
);
|
||||
}
|
||||
if(! intval($x[0]['app_system'])) {
|
||||
build_sync_packet($uid,array('app' => $x));
|
||||
Libsync::build_sync_packet($uid,array('app' => $x));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -959,9 +960,6 @@ class Apps {
|
||||
if($list) {
|
||||
foreach($list as $li) {
|
||||
$papp = self::app_encode($li);
|
||||
if($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false)
|
||||
continue;
|
||||
|
||||
$syslist[] = $papp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,23 @@ namespace Zotlabs\Lib;
|
||||
*/
|
||||
|
||||
class Cache {
|
||||
public static function get($key) {
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
|
||||
dbesc($hash)
|
||||
$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'))
|
||||
);
|
||||
|
||||
if ($r)
|
||||
@@ -40,12 +51,4 @@ class Cache {
|
||||
dbesc(datetime_convert()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function clear() {
|
||||
q("DELETE FROM cache WHERE updated < '%s'",
|
||||
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
/**
|
||||
* @brief A class with chatroom related static methods.
|
||||
*/
|
||||
@@ -91,7 +93,7 @@ class Chatroom {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
build_sync_packet($channel['channel_id'],array('chatroom' => $r));
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('chatroom' => $r));
|
||||
|
||||
q("delete from chatroom where cr_id = %d",
|
||||
intval($r[0]['cr_id'])
|
||||
|
||||
312
Zotlabs/Lib/Connect.php
Normal file
312
Zotlabs/Lib/Connect.php
Normal file
@@ -0,0 +1,312 @@
|
||||
<?php /** @file */
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Daemon\Master;
|
||||
|
||||
|
||||
|
||||
class Connect {
|
||||
|
||||
/**
|
||||
* Takes a $channel and a $url/handle and adds a new connection
|
||||
*
|
||||
* Returns array
|
||||
* $return['success'] boolean true if successful
|
||||
* $return['abook'] Address book entry joined with xchan if successful
|
||||
* $return['message'] error text if success is false.
|
||||
*
|
||||
* This function does NOT send sync packets to clones. The caller is responsible for doing this
|
||||
*/
|
||||
|
||||
static function connect($channel, $url, $sub_channel = false) {
|
||||
|
||||
$uid = $channel['channel_id'];
|
||||
|
||||
if (strpos($url,'@') === false && strpos($url,'/') === false) {
|
||||
$url = $url . '@' . App::get_hostname();
|
||||
}
|
||||
|
||||
$result = [ 'success' => false, 'message' => '' ];
|
||||
|
||||
$my_perms = false;
|
||||
$protocol = '';
|
||||
|
||||
if (substr($url,0,1) === '[') {
|
||||
$x = strpos($url,']');
|
||||
if ($x) {
|
||||
$protocol = substr($url,1,$x-1);
|
||||
$url = substr($url,$x+1);
|
||||
}
|
||||
}
|
||||
|
||||
if (! check_siteallowed($url)) {
|
||||
$result['message'] = t('Channel is blocked on this site.');
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (! $url) {
|
||||
$result['message'] = t('Channel location missing.');
|
||||
return $result;
|
||||
}
|
||||
|
||||
// check service class limits
|
||||
|
||||
$r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ",
|
||||
intval($uid)
|
||||
);
|
||||
if ($r) {
|
||||
$total_channels = $r[0]['total'];
|
||||
}
|
||||
|
||||
if (! service_class_allows($uid,'total_channels',$total_channels)) {
|
||||
$result['message'] = upgrade_message();
|
||||
return $result;
|
||||
}
|
||||
|
||||
$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 ",
|
||||
dbesc($url),
|
||||
dbesc($url),
|
||||
dbesc($url)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
|
||||
// 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');
|
||||
|
||||
}
|
||||
|
||||
$singleton = false;
|
||||
$d = false;
|
||||
|
||||
if (! $r) {
|
||||
|
||||
// not in cache - try discovery
|
||||
|
||||
$wf = discover_by_webbie($url,$protocol);
|
||||
|
||||
if (! $wf) {
|
||||
$feeds = get_config('system','feed_contacts');
|
||||
|
||||
if (($feeds) && (in_array($protocol, [ '', 'feed', 'rss' ]))) {
|
||||
$d = discover_by_url($url);
|
||||
}
|
||||
else {
|
||||
$result['message'] = t('Remote channel or protocol unavailable.');
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($wf || $d) {
|
||||
|
||||
// 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($url),
|
||||
dbesc($url)
|
||||
);
|
||||
|
||||
// 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');
|
||||
}
|
||||
}
|
||||
|
||||
// if discovery was a success or the channel was already cached we should have an xchan record in $r
|
||||
|
||||
if ($r) {
|
||||
$xchan = $r;
|
||||
$xchan_hash = $r['xchan_hash'];
|
||||
$their_perms = EMPTY_STR;
|
||||
}
|
||||
|
||||
// failure case
|
||||
|
||||
if (! $xchan_hash) {
|
||||
$result['message'] = t('Channel discovery failed.');
|
||||
logger('follow: ' . $result['message']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (! check_channelallowed($xchan_hash)) {
|
||||
$result['message'] = t('Channel is blocked on this site.');
|
||||
logger('follow: ' . $result['message']);
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
$allowed = ((in_array($xchan['xchan_network'],['rss','zot','zot6'])) ? 1 : 0);
|
||||
|
||||
$hookdata = ['channel_id' => $uid, 'follow_address' => $url, 'xchan' => $xchan, 'allowed' => $allowed, 'singleton' => 0];
|
||||
call_hooks('follow_allow',$hookdata);
|
||||
|
||||
if(! $hookdata['allowed']) {
|
||||
$result['message'] = t('Protocol disabled.');
|
||||
return $result;
|
||||
}
|
||||
|
||||
$singleton = intval($hookdata['singleton']);
|
||||
|
||||
// Now start processing the new connection
|
||||
|
||||
$aid = $channel['channel_account_id'];
|
||||
$default_group = $channel['channel_default_group'];
|
||||
|
||||
if (in_array($xchan_hash, [$channel['channel_hash'], $channel['channel_portable_id']])) {
|
||||
$result['message'] = t('Cannot connect to yourself.');
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($xchan['xchan_network'] === 'rss') {
|
||||
|
||||
// check service class feed limits
|
||||
|
||||
$t = q("select count(*) as total from abook where abook_account = %d and abook_feed = 1 ",
|
||||
intval($aid)
|
||||
);
|
||||
if ($t) {
|
||||
$total_feeds = $t[0]['total'];
|
||||
}
|
||||
|
||||
if (! service_class_allows($uid,'total_feeds',$total_feeds)) {
|
||||
$result['message'] = upgrade_message();
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Always set these "remote" permissions for feeds since we cannot interact with them
|
||||
// to negotiate a suitable permission response
|
||||
|
||||
set_abconfig($uid,$xchan_hash,'their_perms','view_stream',1);
|
||||
set_abconfig($uid,$xchan_hash,'their_perms','republish',1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
$p = Permissions::connect_perms($uid);
|
||||
|
||||
// parent channels have unencumbered write permission
|
||||
|
||||
if ($sub_channel) {
|
||||
$p['perms']['post_wall'] = 1;
|
||||
$p['perms']['post_comments'] = 1;
|
||||
$p['perms']['write_storage'] = 1;
|
||||
$p['perms']['post_like'] = 1;
|
||||
$p['perms']['delegate'] = 0;
|
||||
$p['perms']['moderated'] = 0;
|
||||
}
|
||||
|
||||
$my_perms = $p['perms'];
|
||||
|
||||
$profile_assign = get_pconfig($uid,'system','profile_assign','');
|
||||
|
||||
|
||||
// See if we are already connected by virtue of having an abook record
|
||||
|
||||
$r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook
|
||||
where abook_xchan = '%s' and abook_channel = %d limit 1",
|
||||
dbesc($xchan_hash),
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
|
||||
$abook_instance = $r[0]['abook_instance'];
|
||||
|
||||
// If they are on a non-nomadic network, add them to this location
|
||||
|
||||
if (($singleton) && strpos($abook_instance,z_root()) === false) {
|
||||
if ($abook_instance) {
|
||||
$abook_instance .= ',';
|
||||
}
|
||||
$abook_instance .= z_root();
|
||||
|
||||
$x = q("update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d",
|
||||
dbesc($abook_instance),
|
||||
intval($r[0]['abook_id'])
|
||||
);
|
||||
}
|
||||
|
||||
// if they have a pending connection, we just followed them so approve the connection request
|
||||
|
||||
if (intval($r[0]['abook_pending'])) {
|
||||
$x = q("update abook set abook_pending = 0 where abook_id = %d",
|
||||
intval($r[0]['abook_id'])
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// create a new abook record
|
||||
|
||||
$closeness = get_pconfig($uid,'system','new_abook_closeness',80);
|
||||
|
||||
$r = abook_store_lowlevel(
|
||||
[
|
||||
'abook_account' => intval($aid),
|
||||
'abook_channel' => intval($uid),
|
||||
'abook_closeness' => intval($closeness),
|
||||
'abook_xchan' => $xchan_hash,
|
||||
'abook_profile' => $profile_assign,
|
||||
'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0),
|
||||
'abook_created' => datetime_convert(),
|
||||
'abook_updated' => datetime_convert(),
|
||||
'abook_instance' => (($singleton) ? z_root() : '')
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if (! $r) {
|
||||
logger('abook creation failed');
|
||||
$result['message'] = t('error saving data');
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Set suitable permissions to the connection
|
||||
|
||||
if($my_perms) {
|
||||
foreach($my_perms as $k => $v) {
|
||||
set_abconfig($uid,$xchan_hash,'my_perms',$k,$v);
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the entire record
|
||||
|
||||
$r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
|
||||
where abook_xchan = '%s' and abook_channel = %d limit 1",
|
||||
dbesc($xchan_hash),
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$result['abook'] = array_shift($r);
|
||||
Master::Summon([ 'Notifier', 'permission_create', $result['abook']['abook_id'] ]);
|
||||
}
|
||||
|
||||
$arr = [ 'channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook'] ];
|
||||
|
||||
call_hooks('follow', $arr);
|
||||
|
||||
/** If there is a default group for this channel, add this connection to it */
|
||||
|
||||
if ($default_group) {
|
||||
$g = AccessList::rec_byhash($uid,$default_group);
|
||||
if ($g) {
|
||||
AccessList::member_add($uid,'',$xchan_hash,$g['id']);
|
||||
}
|
||||
}
|
||||
|
||||
$result['success'] = true;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -58,10 +58,15 @@ class DB_Upgrade {
|
||||
|
||||
|
||||
$c = new $cls();
|
||||
|
||||
$retval = $c->run();
|
||||
|
||||
if($retval != UPDATE_SUCCESS) {
|
||||
|
||||
|
||||
$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.
|
||||
|
||||
@@ -86,7 +91,9 @@ class DB_Upgrade {
|
||||
'$sitename' => \App::$config['system']['sitename'],
|
||||
'$siteurl' => z_root(),
|
||||
'$update' => $x,
|
||||
'$error' => sprintf( t('Update %s failed. See error logs.'), $x)
|
||||
'$error' => sprintf( t('Update %s failed. See error logs.'), $x),
|
||||
'$baseurl' => z_root(),
|
||||
'$source' => $source
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -118,7 +118,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'] === $rxchan) && ($dr['status'] === 'recipient not found'))
|
||||
return false;
|
||||
|
||||
// If you have a private post with a recipient list, every single site is going to report
|
||||
|
||||
@@ -143,19 +143,26 @@ class Enotify {
|
||||
|
||||
$action = t('commented on');
|
||||
|
||||
if(array_key_exists('item',$params) && in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
|
||||
if(array_key_exists('item',$params)) {
|
||||
|
||||
if(in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
|
||||
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_LIKE))
|
||||
$action = t('liked');
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_DISLIKE))
|
||||
$action = t('disliked');
|
||||
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_LIKE))
|
||||
$action = t('liked');
|
||||
|
||||
if(activity_match($params['verb'], ACTIVITY_DISLIKE))
|
||||
$action = t('disliked');
|
||||
if($params['item']['obj_type'] === 'Answer')
|
||||
$action = t('voted on');
|
||||
|
||||
}
|
||||
|
||||
@@ -550,6 +557,11 @@ class Enotify {
|
||||
if ((\App::$language === 'en' || (! \App::$language)) && strpos($msg,', '))
|
||||
$msg = substr($msg,strpos($msg,', ')+1);
|
||||
|
||||
$datarray['id'] = $notify_id;
|
||||
$datarray['msg'] = $msg;
|
||||
|
||||
call_hooks('enotify_store_end', $datarray);
|
||||
|
||||
$r = q("update notify set msg = '%s' where id = %d and uid = %d",
|
||||
dbesc($msg),
|
||||
intval($notify_id),
|
||||
@@ -754,9 +766,9 @@ class Enotify {
|
||||
// generate a multipart/alternative message header
|
||||
$messageHeader =
|
||||
$params['additionalMailHeader'] .
|
||||
"From: $fromName <{$params['fromEmail']}>\n" .
|
||||
"Reply-To: $fromName <{$params['replyTo']}>\n" .
|
||||
"MIME-Version: 1.0\n" .
|
||||
"From: $fromName <{$params['fromEmail']}>" . PHP_EOL .
|
||||
"Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL .
|
||||
"MIME-Version: 1.0" . PHP_EOL .
|
||||
"Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\"";
|
||||
|
||||
// assemble the final multipart message body with the text and html types included
|
||||
@@ -764,15 +776,15 @@ class Enotify {
|
||||
$htmlBody = chunk_split(base64_encode($params['htmlVersion']));
|
||||
|
||||
$multipartMessageBody =
|
||||
"--" . $mimeBoundary . "\n" . // plain text section
|
||||
"Content-Type: text/plain; charset=UTF-8\n" .
|
||||
"Content-Transfer-Encoding: base64\n\n" .
|
||||
$textBody . "\n" .
|
||||
"--" . $mimeBoundary . "\n" . // text/html section
|
||||
"Content-Type: text/html; charset=UTF-8\n" .
|
||||
"Content-Transfer-Encoding: base64\n\n" .
|
||||
$htmlBody . "\n" .
|
||||
"--" . $mimeBoundary . "--\n"; // message ending
|
||||
"--" . $mimeBoundary . PHP_EOL . // plain text section
|
||||
"Content-Type: text/plain; charset=UTF-8" . PHP_EOL .
|
||||
"Content-Transfer-Encoding: base64" . PHP_EOL . PHP_EOL .
|
||||
$textBody . PHP_EOL .
|
||||
"--" . $mimeBoundary . PHP_EOL . // text/html section
|
||||
"Content-Type: text/html; charset=UTF-8" . PHP_EOL .
|
||||
"Content-Transfer-Encoding: base64" . PHP_EOL . PHP_EOL .
|
||||
$htmlBody . PHP_EOL .
|
||||
"--" . $mimeBoundary . "--" . PHP_EOL; // message ending
|
||||
|
||||
// send the message
|
||||
$res = mail(
|
||||
@@ -805,8 +817,17 @@ class Enotify {
|
||||
}
|
||||
else {
|
||||
$itemem_text = (($item['item_thread_top'])
|
||||
? t('created a new post')
|
||||
: sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name']));
|
||||
? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post'))
|
||||
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
|
||||
);
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
$edit = false;
|
||||
@@ -825,21 +846,24 @@ class Enotify {
|
||||
|
||||
// convert this logic into a json array just like the system notifications
|
||||
|
||||
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
|
||||
|
||||
$x = array(
|
||||
'notify_link' => $item['llink'],
|
||||
'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' => relative_date(($edit)? $item['edited'] : $item['created']),
|
||||
'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'],
|
||||
'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' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
|
||||
'notify_id' => 'undefined',
|
||||
'b64mid' => (($item['mid']) ? 'b64.' . base64url_encode($item['mid']) : ''),
|
||||
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
|
||||
'thread_top' => (($item['item_thread_top']) ? true : false),
|
||||
'message' => strip_tags(bbcode($itemem_text)),
|
||||
'message' => bbcode(escape_tags($itemem_text)),
|
||||
'body' => htmlentities(html2plain(bbcode($item['body']), 75, true), ENT_COMPAT, 'UTF-8', false),
|
||||
// these are for the superblock addon
|
||||
'hash' => $item['author']['xchan_hash'],
|
||||
'uid' => local_channel(),
|
||||
'hash' => $item[$who]['xchan_hash'],
|
||||
'uid' => $item['uid'],
|
||||
'display' => true
|
||||
);
|
||||
|
||||
@@ -851,4 +875,118 @@ class Enotify {
|
||||
return $x;
|
||||
}
|
||||
|
||||
static public function format_notify($tt) {
|
||||
|
||||
$message = trim(strip_tags(bbcode($tt['msg'])));
|
||||
|
||||
if(strpos($message, $tt['xname']) === 0)
|
||||
$message = substr($message, strlen($tt['xname']) + 1);
|
||||
|
||||
$mid = basename($tt['link']);
|
||||
|
||||
$b64mid = ((strpos($mid, 'b64.') === 0) ? $mid : 'b64.' . base64url_encode($mid));
|
||||
$x = [
|
||||
'notify_link' => z_root() . '/notify/view/' . $tt['id'],
|
||||
'name' => $tt['xname'],
|
||||
'url' => $tt['url'],
|
||||
'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 : ''),
|
||||
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''),
|
||||
'message' => $message
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_intros($rr) {
|
||||
|
||||
$x = [
|
||||
'notify_link' => z_root() . '/connections/ifpending',
|
||||
'name' => $rr['xchan_name'],
|
||||
'addr' => $rr['xchan_addr'],
|
||||
'url' => $rr['xchan_url'],
|
||||
'photo' => $rr['xchan_photo_s'],
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['abook_created']),
|
||||
'hclass' => ('notify-unseen'),
|
||||
'message' => t('added your channel')
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_files($rr) {
|
||||
|
||||
$x = [
|
||||
'notify_link' => z_root() . '/sharedwithme',
|
||||
'name' => $rr['author']['xchan_name'],
|
||||
'addr' => $rr['author']['xchan_addr'],
|
||||
'url' => $rr['author']['xchan_url'],
|
||||
'photo' => $rr['author']['xchan_photo_s'],
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']),
|
||||
'hclass' => ('notify-unseen'),
|
||||
'message' => t('shared a file with you')
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_mail($rr) {
|
||||
|
||||
$x = [
|
||||
'notify_link' => z_root() . '/mail/' . $rr['id'],
|
||||
'name' => $rr['xchan_name'],
|
||||
'addr' => $rr['xchan_addr'],
|
||||
'url' => $rr['xchan_url'],
|
||||
'photo' => $rr['xchan_photo_s'],
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']),
|
||||
'hclass' => (intval($rr['mail_seen']) ? 'notify-seen' : 'notify-unseen'),
|
||||
'message' => t('sent you a private message'),
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_all_events($rr) {
|
||||
|
||||
$bd_format = t('g A l F d') ; // 8 AM Friday January 18
|
||||
$strt = datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart']);
|
||||
$today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false);
|
||||
$when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
|
||||
|
||||
$x = [
|
||||
'notify_link' => z_root() . '/cdav/calendar/' . $rr['event_hash'],
|
||||
'name' => $rr['xchan_name'],
|
||||
'addr' => $rr['xchan_addr'],
|
||||
'url' => $rr['xchan_url'],
|
||||
'photo' => $rr['xchan_photo_s'],
|
||||
'when' => $when,
|
||||
'hclass' => (($today) ? 'notify-unseen bg-warning' : 'notify-unseen'),
|
||||
'message' => t('created an event')
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_register($rr) {
|
||||
|
||||
$x = [
|
||||
'notify_link' => z_root() . '/admin/accounts',
|
||||
'name' => $rr['account_email'],
|
||||
//'addr' => $rr['account_email'],
|
||||
'photo' => z_root() . '/' . get_default_profile_photo(48),
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(),$rr['account_created']),
|
||||
'hclass' => ('notify-unseen'),
|
||||
'message' => t('requires approval')
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
class JSalmon {
|
||||
|
||||
@@ -51,7 +51,7 @@ class JSalmon {
|
||||
. base64url_encode($x['encoding'],true) . '.'
|
||||
. base64url_encode($x['alg'],true);
|
||||
|
||||
$key = HTTPSig::get_key(EMPTY_STR,base64url_decode($x['sigs']['key_id']));
|
||||
$key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id']));
|
||||
logger('key: ' . print_r($key,true));
|
||||
if($key['portable_id'] && $key['public_key']) {
|
||||
if(rsa_verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {
|
||||
@@ -69,4 +69,4 @@ class JSalmon {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ class LDSignatures {
|
||||
$options = [
|
||||
'type' => 'RsaSignature2017',
|
||||
'nonce' => random_string(64),
|
||||
'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
|
||||
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
|
||||
'creator' => z_root() . '/channel/' . $channel['channel_address'],
|
||||
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z')
|
||||
];
|
||||
|
||||
$ohash = self::hash(self::signable_options($options));
|
||||
@@ -93,7 +93,8 @@ class LDSignatures {
|
||||
$d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
logger('normalise error:' . print_r($e,true));
|
||||
// Don't log the exception - this can exhaust memory
|
||||
// logger('normalise error:' . print_r($e,true));
|
||||
logger('normalise error: ' . print_r($data,true));
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ class LDSignatures {
|
||||
'meDataType' => $data_type,
|
||||
'meEncoding' => $encoding,
|
||||
'meAlgorithm' => $algorithm,
|
||||
'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
|
||||
'meCreator' => z_root() . '/channel/' . $channel['channel_address'],
|
||||
'meSignatureValue' => $signature
|
||||
]);
|
||||
|
||||
@@ -132,4 +133,4 @@ class LDSignatures {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class Libsync {
|
||||
|
||||
$channel = $r[0];
|
||||
|
||||
// don't provide these in the export
|
||||
// don't provide these in the export
|
||||
|
||||
unset($channel['channel_active']);
|
||||
unset($channel['channel_password']);
|
||||
@@ -83,7 +83,7 @@ class Libsync {
|
||||
|
||||
$info = (($packet) ? $packet : array());
|
||||
$info['type'] = 'sync';
|
||||
$info['encoding'] = 'red'; // note: not zot, this packet is very platform specific
|
||||
$info['encoding'] = 'hz'; // note: not zot, this packet is very platform specific
|
||||
$info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root() ];
|
||||
|
||||
if(array_key_exists($uid,\App::$config) && array_key_exists('transient',\App::$config[$uid])) {
|
||||
@@ -144,12 +144,13 @@ class Libsync {
|
||||
|
||||
foreach($synchubs as $hub) {
|
||||
$hash = random_string();
|
||||
$n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'red',$hub['hubloc_sitekey'],$hub['site_crypto']);
|
||||
$n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'hz',$hub['hubloc_sitekey'],$hub['site_crypto']);
|
||||
Queue::insert(array(
|
||||
'hash' => $hash,
|
||||
'account_id' => $channel['channel_account_id'],
|
||||
'channel_id' => $channel['channel_id'],
|
||||
'posturl' => $hub['hubloc_callback'],
|
||||
'driver' => $hub['hubloc_network'],
|
||||
'notify' => $n,
|
||||
'msg' => EMPTY_STR
|
||||
));
|
||||
@@ -244,7 +245,13 @@ class Libsync {
|
||||
|
||||
if(array_key_exists('app',$arr) && $arr['app'])
|
||||
sync_apps($channel,$arr['app']);
|
||||
|
||||
|
||||
if(array_key_exists('addressbook',$arr) && $arr['addressbook'])
|
||||
sync_addressbook($channel,$arr['addressbook']);
|
||||
|
||||
if(array_key_exists('calendar',$arr) && $arr['calendar'])
|
||||
sync_calendar($channel,$arr['calendar']);
|
||||
|
||||
if(array_key_exists('chatroom',$arr) && $arr['chatroom'])
|
||||
sync_chatrooms($channel,$arr['chatroom']);
|
||||
|
||||
@@ -253,7 +260,7 @@ class Libsync {
|
||||
|
||||
if(array_key_exists('mail',$arr) && $arr['mail'])
|
||||
sync_mail($channel,$arr['mail']);
|
||||
|
||||
|
||||
if(array_key_exists('event',$arr) && $arr['event'])
|
||||
sync_events($channel,$arr['event']);
|
||||
|
||||
@@ -262,7 +269,7 @@ class Libsync {
|
||||
|
||||
if(array_key_exists('item',$arr) && $arr['item'])
|
||||
sync_items($channel,$arr['item'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null));
|
||||
|
||||
|
||||
// deprecated, maintaining for a few months for upward compatibility
|
||||
// this should sync webpages, but the logic is a bit subtle
|
||||
|
||||
@@ -271,7 +278,7 @@ class Libsync {
|
||||
|
||||
if(array_key_exists('menu',$arr) && $arr['menu'])
|
||||
sync_menus($channel,$arr['menu']);
|
||||
|
||||
|
||||
if(array_key_exists('file',$arr) && $arr['file'])
|
||||
sync_files($channel,$arr['file']);
|
||||
|
||||
@@ -286,7 +293,7 @@ class Libsync {
|
||||
if(array_key_exists('channel_pageflags',$arr['channel']) && intval($arr['channel']['channel_pageflags'])) {
|
||||
|
||||
// Several pageflags are site-specific and cannot be sync'd.
|
||||
// Only allow those bits which are shareable from the remote and then
|
||||
// Only allow those bits which are shareable from the remote and then
|
||||
// logically OR with the local flags
|
||||
|
||||
$arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] & (PAGE_HIDDEN|PAGE_AUTOCONNECT|PAGE_APPLICATION|PAGE_PREMIUM|PAGE_ADULT);
|
||||
@@ -336,7 +343,7 @@ class Libsync {
|
||||
|
||||
$disallowed = array('abook_id','abook_account','abook_channel','abook_rating','abook_rating_text','abook_not_here');
|
||||
|
||||
$fields = db_columns($abook);
|
||||
$fields = db_columns('abook');
|
||||
|
||||
foreach($arr['abook'] as $abook) {
|
||||
|
||||
@@ -555,7 +562,7 @@ class Libsync {
|
||||
// our group list is already synchronised
|
||||
if($x) {
|
||||
foreach($x as $y) {
|
||||
|
||||
|
||||
// for each group, loop on members list we just received
|
||||
if(isset($y['hash']) && isset($members[$y['hash']])) {
|
||||
foreach($members[$y['hash']] as $member) {
|
||||
@@ -567,9 +574,9 @@ class Libsync {
|
||||
);
|
||||
if($z)
|
||||
$found = true;
|
||||
|
||||
|
||||
// if somebody is in the group that wasn't before - add them
|
||||
|
||||
|
||||
if(! $found) {
|
||||
q("INSERT INTO pgrp_member (uid, gid, xchan)
|
||||
VALUES( %d, %d, '%s' ) ",
|
||||
@@ -580,7 +587,7 @@ class Libsync {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// now retrieve a list of members we have on this site
|
||||
$m = q("select xchan from pgrp_member where gid = %d and uid = %d",
|
||||
intval($y['id']),
|
||||
@@ -608,7 +615,7 @@ class Libsync {
|
||||
$disallowed = array('id','aid','uid','guid');
|
||||
|
||||
foreach($arr['profile'] as $profile) {
|
||||
|
||||
|
||||
$x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1",
|
||||
dbesc($profile['profile_guid']),
|
||||
intval($channel['channel_id'])
|
||||
@@ -621,7 +628,7 @@ class Libsync {
|
||||
'profile_guid' => $profile['profile_guid'],
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
$x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1",
|
||||
dbesc($profile['profile_guid']),
|
||||
intval($channel['channel_id'])
|
||||
@@ -768,14 +775,14 @@ class Libsync {
|
||||
);
|
||||
if($r) {
|
||||
logger('Hub exists: ' . $location['url'], LOGGER_DEBUG);
|
||||
|
||||
|
||||
// update connection timestamp if this is the site we're talking to
|
||||
// This only happens when called from import_xchan
|
||||
|
||||
$current_site = false;
|
||||
|
||||
$t = datetime_convert('UTC','UTC','now - 15 minutes');
|
||||
|
||||
|
||||
if(array_key_exists('site',$arr) && $location['url'] == $arr['site']['url']) {
|
||||
q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_connected < '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
@@ -812,9 +819,9 @@ class Libsync {
|
||||
}
|
||||
|
||||
if(intval($r[0]['hubloc_primary']) && (! $location['primary'])) {
|
||||
$m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id = %d",
|
||||
$m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
intval($r[0]['hubloc_id'])
|
||||
dbesc($r[0]['hubloc_id_url'])
|
||||
);
|
||||
$r[0]['hubloc_primary'] = intval($location['primary']);
|
||||
hubloc_change_primary($r[0]);
|
||||
@@ -841,18 +848,18 @@ class Libsync {
|
||||
}
|
||||
}
|
||||
if(intval($r[0]['hubloc_deleted']) && (! intval($location['deleted']))) {
|
||||
$n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id = %d",
|
||||
$n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
intval($r[0]['hubloc_id'])
|
||||
dbesc($r[0]['hubloc_id_url'])
|
||||
);
|
||||
$what .= 'undelete_hub ';
|
||||
$changed = true;
|
||||
}
|
||||
elseif((! intval($r[0]['hubloc_deleted'])) && (intval($location['deleted']))) {
|
||||
logger('deleting hubloc: ' . $r[0]['hubloc_addr']);
|
||||
$n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d",
|
||||
$n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
intval($r[0]['hubloc_id'])
|
||||
dbesc($r[0]['hubloc_id_url'])
|
||||
);
|
||||
$what .= 'delete_hub ';
|
||||
$changed = true;
|
||||
@@ -896,12 +903,14 @@ class Libsync {
|
||||
$changed = true;
|
||||
|
||||
if($location['primary']) {
|
||||
$r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s' limit 1",
|
||||
$r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s'",
|
||||
dbesc($location['address']),
|
||||
dbesc($location['sitekey'])
|
||||
);
|
||||
if($r)
|
||||
hubloc_change_primary($r[0]);
|
||||
if($r) {
|
||||
$r = Libzot::zot_record_preferred($r);
|
||||
hubloc_change_primary($r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,9 +920,9 @@ class Libsync {
|
||||
foreach($xisting as $x) {
|
||||
if(! array_key_exists('updated',$x)) {
|
||||
logger('Deleting unreferenced hub location ' . $x['hubloc_addr']);
|
||||
$r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d",
|
||||
$r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
intval($x['hubloc_id'])
|
||||
dbesc($x['hubloc_id_url'])
|
||||
);
|
||||
$what .= 'removed_hub ';
|
||||
$changed = true;
|
||||
@@ -1016,4 +1025,4 @@ class Libsync {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Access\PermissionLimits;
|
||||
use Zotlabs\Daemon\Master;
|
||||
@@ -105,7 +105,7 @@ class Libzot {
|
||||
$data = [
|
||||
'type' => $type,
|
||||
'encoding' => $encoding,
|
||||
'sender' => $channel['channel_portable_id'],
|
||||
'sender' => $channel['channel_hash'],
|
||||
'site_id' => self::make_xchan_hash(z_root(), get_config('system','pubkey')),
|
||||
'version' => System::get_zot_revision(),
|
||||
];
|
||||
@@ -316,16 +316,20 @@ class Libzot {
|
||||
|
||||
$x = self::import_xchan($record['data'], (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
|
||||
|
||||
|
||||
if(! $x['success'])
|
||||
return false;
|
||||
|
||||
if($channel && $record['data']['permissions']) {
|
||||
$permissions = explode(',',$record['data']['permissions']);
|
||||
|
||||
if($permissions && is_array($permissions)) {
|
||||
$old_read_stream_perm = get_abconfig($channel['channel_id'],$x['hash'],'their_perms','view_stream');
|
||||
|
||||
foreach($permissions as $p) {
|
||||
set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$p,'1');
|
||||
$permissions = Permissions::FilledPerms($permissions);
|
||||
|
||||
foreach($permissions as $k => $v) {
|
||||
set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$k,$v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +426,7 @@ class Libzot {
|
||||
[
|
||||
'type' => NOTIFY_INTRO,
|
||||
'from_xchan' => $x['hash'],
|
||||
'to_xchan' => $channel['channel_portable_id'],
|
||||
'to_xchan' => $channel['channel_hash'],
|
||||
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']
|
||||
]
|
||||
);
|
||||
@@ -788,7 +792,7 @@ class Libzot {
|
||||
|
||||
// see if this is a channel clone that's hosted locally - which we treat different from other xchans/connections
|
||||
|
||||
$local = q("select channel_account_id, channel_id from channel where channel_portable_id = '%s' limit 1",
|
||||
$local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1",
|
||||
dbesc($xchan_hash)
|
||||
);
|
||||
if($local) {
|
||||
@@ -1133,6 +1137,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
logger($AS->debug(),LOGGER_DATA);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1151,7 +1156,7 @@ class Libzot {
|
||||
if($recip_arr) {
|
||||
stringify_array_elms($recip_arr,true);
|
||||
$recips = implode(',',$recip_arr);
|
||||
$r = q("select channel_portable_id as hash from channel where channel_portable_id in ( " . $recips . " ) and channel_removed = 0 ");
|
||||
$r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and channel_removed = 0 ");
|
||||
}
|
||||
|
||||
if(! $r) {
|
||||
@@ -1193,18 +1198,20 @@ class Libzot {
|
||||
|
||||
if(in_array($env['type'],['activity','response'])) {
|
||||
|
||||
$arr = Activity::decode_note($AS);
|
||||
|
||||
//logger($AS->debug());
|
||||
|
||||
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
$r = q("select hubloc_hash, hubloc_network from hubloc where hubloc_id_url = '%s' ",
|
||||
dbesc($AS->actor['id'])
|
||||
);
|
||||
|
||||
if($r) {
|
||||
$arr['author_xchan'] = $r[0]['hubloc_hash'];
|
||||
// selects a zot6 hash if available, otherwise use whatever we have
|
||||
$r = self::zot_record_preferred($r);
|
||||
$arr['author_xchan'] = $r['hubloc_hash'];
|
||||
}
|
||||
|
||||
if (! $arr['author_xchan']) {
|
||||
logger('No author!');
|
||||
return;
|
||||
}
|
||||
|
||||
$s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($env['sender'])
|
||||
@@ -1218,12 +1225,42 @@ class Libzot {
|
||||
$arr['owner_xchan'] = $env['sender'];
|
||||
}
|
||||
|
||||
if($private) {
|
||||
$arr['item_private'] = true;
|
||||
if ($private && (! intval($arr['item_private']))) {
|
||||
$arr['item_private'] = 1;
|
||||
}
|
||||
|
||||
if ($arr['mid'] === $arr['parent_mid']) {
|
||||
if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) {
|
||||
$p = strstr($AS->obj['commentPolicy'],'until=');
|
||||
if($p !== false) {
|
||||
$arr['comments_closed'] = datetime_convert('UTC','UTC', substr($p,6));
|
||||
$arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy']));
|
||||
}
|
||||
else {
|
||||
$arr['comment_policy'] = $AS->obj['commentPolicy'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @FIXME - spoofable
|
||||
if($AS->data['hubloc']) {
|
||||
$arr['item_verified'] = true;
|
||||
|
||||
if (! array_key_exists('comment_policy',$arr)) {
|
||||
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
|
||||
// Anything else we'll say is zot - which could have a range of project names
|
||||
$s = q("select site_project from site where site_url = '%s' limit 1",
|
||||
dbesc($r[0]['hubloc_url'])
|
||||
);
|
||||
|
||||
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
|
||||
$arr['comment_policy'] = 'authenticated';
|
||||
}
|
||||
else {
|
||||
$arr['comment_policy'] = 'contacts';
|
||||
}
|
||||
}
|
||||
}
|
||||
if($AS->data['signed_data']) {
|
||||
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
||||
@@ -1245,7 +1282,12 @@ class Libzot {
|
||||
logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
|
||||
logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
|
||||
|
||||
$result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries);
|
||||
if ($env['encoding'] === 'hz') {
|
||||
$result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries);
|
||||
}
|
||||
else {
|
||||
logger('sync packet type not supported.');
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($result) {
|
||||
@@ -1331,12 +1373,12 @@ class Libzot {
|
||||
|
||||
$r = [];
|
||||
|
||||
$c = q("select channel_id, channel_portable_id from channel where channel_removed = 0");
|
||||
$c = q("select channel_id, channel_hash from channel where channel_removed = 0");
|
||||
|
||||
if($c) {
|
||||
foreach($c as $cc) {
|
||||
if(perm_is_allowed($cc['channel_id'],$msg['sender'],$perm)) {
|
||||
$r[] = $cc['channel_portable_id'];
|
||||
$r[] = $cc['channel_hash'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1344,7 +1386,7 @@ class Libzot {
|
||||
if($include_sys) {
|
||||
$sys = get_sys_channel();
|
||||
if($sys)
|
||||
$r[] = $sys['channel_portable_id'];
|
||||
$r[] = $sys['channel_hash'];
|
||||
}
|
||||
|
||||
|
||||
@@ -1360,7 +1402,7 @@ class Libzot {
|
||||
if($tag['type'] === 'Mention' && (strpos($tag['href'],z_root()) !== false)) {
|
||||
$address = basename($tag['href']);
|
||||
if($address) {
|
||||
$z = q("select channel_portable_id as hash from channel where channel_address = '%s'
|
||||
$z = q("select channel_hash as hash from channel where channel_address = '%s'
|
||||
and channel_removed = 0 limit 1",
|
||||
dbesc($address)
|
||||
);
|
||||
@@ -1381,7 +1423,7 @@ class Libzot {
|
||||
$thread_parent = self::find_parent($msg,$act);
|
||||
|
||||
if($thread_parent) {
|
||||
$z = q("select channel_portable_id as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
|
||||
$z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
|
||||
dbesc($thread_parent),
|
||||
dbesc($thread_parent)
|
||||
);
|
||||
@@ -1436,7 +1478,7 @@ class Libzot {
|
||||
|
||||
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
|
||||
|
||||
$channel = channelx_by_portid($d);
|
||||
$channel = channelx_by_hash($d);
|
||||
|
||||
if (! $channel) {
|
||||
$DR->update('recipient not found');
|
||||
@@ -1447,22 +1489,23 @@ class Libzot {
|
||||
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
|
||||
|
||||
if(($act) && ($act->obj) && (! is_array($act->obj))) {
|
||||
// The initial object fetch failed using the sys channel credentials.
|
||||
// The initial object fetch failed using the sys channel credentials.
|
||||
// Try again using the delivery channel credentials.
|
||||
// We will also need to re-parse the $item array,
|
||||
// We will also need to re-parse the $item array,
|
||||
// but preserve any values that were set during anonymous parsing.
|
||||
|
||||
|
||||
$o = Activity::fetch($act->obj,$channel);
|
||||
if($o) {
|
||||
$act->obj = $o;
|
||||
$arr = array_merge(Activity::decode_note($act),$arr);
|
||||
}
|
||||
else {
|
||||
|
||||
$DR->update('Incomplete or corrupt activity');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to block normal top-level message delivery from our clones, as the delivered
|
||||
@@ -1473,7 +1516,7 @@ class Libzot {
|
||||
* access checks.
|
||||
*/
|
||||
|
||||
if($sender === $channel['channel_portable_id'] && $arr['author_xchan'] === $channel['channel_portable_id'] && $arr['mid'] === $arr['parent_mid']) {
|
||||
if($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && $arr['mid'] === $arr['parent_mid']) {
|
||||
$DR->update('self delivery ignored');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
@@ -1576,10 +1619,11 @@ class Libzot {
|
||||
// As a side effect we will also do a preliminary check that we have the top-level-post, otherwise
|
||||
// processing it is pointless.
|
||||
|
||||
$r = q("select route, id, owner_xchan, item_private from item where mid = '%s' and uid = %d limit 1",
|
||||
$r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1",
|
||||
dbesc($arr['parent_mid']),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
$DR->update('comment parent not found');
|
||||
$result[] = $DR->get();
|
||||
@@ -1590,7 +1634,7 @@ class Libzot {
|
||||
// have the copy and we don't want the request to loop.
|
||||
// Also don't do this if this comment came from a conversation request packet.
|
||||
// It's possible that comments are allowed but posting isn't and that could
|
||||
// cause a conversation fetch loop.
|
||||
// cause a conversation fetch loop.
|
||||
// We'll also check the send_stream permission - because if it isn't allowed,
|
||||
// the top level post is unlikely to be imported and
|
||||
// this is just an exercise in futility.
|
||||
@@ -1602,6 +1646,16 @@ class Libzot {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($r[0]['obj_type'] === 'Question') {
|
||||
// route checking doesn't work correctly here because we've changed the privacy
|
||||
$r[0]['route'] = EMPTY_STR;
|
||||
// If this is a poll response, convert the obj_type to our (internal-only) "Answer" type
|
||||
if ($arr['obj_type'] === ACTIVITY_OBJ_COMMENT && $arr['title'] && (! $arr['body'])) {
|
||||
$arr['obj_type'] = 'Answer';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) {
|
||||
// reset the route in case it travelled a great distance upstream
|
||||
// use our parent's route so when we go back downstream we'll match
|
||||
@@ -1669,7 +1723,7 @@ class Libzot {
|
||||
$arr['aid'] = $channel['channel_account_id'];
|
||||
$arr['uid'] = $channel['channel_id'];
|
||||
|
||||
$item_id = self::delete_imported_item($sender,$arr,$channel['channel_id'],$relay);
|
||||
$item_id = self::delete_imported_item($sender,$act,$arr,$channel['channel_id'],$relay);
|
||||
$DR->update(($item_id) ? 'deleted' : 'delete_failed');
|
||||
$result[] = $DR->get();
|
||||
|
||||
@@ -1683,11 +1737,15 @@ class Libzot {
|
||||
continue;
|
||||
}
|
||||
|
||||
// reactions such as like and dislike could have an mid with /activity/ in it.
|
||||
// Check for both forms in order to prevent duplicates.
|
||||
|
||||
$r = q("select * from item where mid = '%s' and uid = %d limit 1",
|
||||
$r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1",
|
||||
dbesc($arr['mid']),
|
||||
dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
if($r) {
|
||||
// We already have this post.
|
||||
$item_id = $r[0]['id'];
|
||||
@@ -1732,7 +1790,7 @@ class Libzot {
|
||||
// if it's a sourced post, call the post_local hooks as if it were
|
||||
// posted locally so that crosspost connectors will be triggered.
|
||||
|
||||
if(check_item_source($arr['uid'], $arr)) {
|
||||
if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) {
|
||||
/**
|
||||
* @hooks post_local
|
||||
* Called when an item has been posted on this machine via mod/item.php (also via API).
|
||||
@@ -1779,7 +1837,7 @@ class Libzot {
|
||||
|
||||
$stored = (($item_result && $item_result['item']) ? $item_result['item'] : false);
|
||||
if((is_array($stored)) && ($stored['id'] != $stored['parent'])
|
||||
&& ($stored['author_xchan'] === $channel['channel_hash'] || $stored['author_xchan'] === $channel['channel_portable_id'])) {
|
||||
&& ($stored['author_xchan'] === $channel['channel_hash'] || $stored['author_xchan'] === $channel['channel_hash'])) {
|
||||
retain_item($stored['item']['parent']);
|
||||
}
|
||||
|
||||
@@ -1817,6 +1875,10 @@ class Libzot {
|
||||
|
||||
$ret = [];
|
||||
|
||||
$signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($a['signature']['signer'])
|
||||
);
|
||||
|
||||
foreach($a['data']['orderedItems'] as $activity) {
|
||||
|
||||
$AS = new ActivityStreams($activity);
|
||||
@@ -1875,14 +1937,31 @@ class Libzot {
|
||||
if($AS->data['hubloc']) {
|
||||
$arr['item_verified'] = true;
|
||||
}
|
||||
|
||||
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
|
||||
// Anything else we'll say is zot - which could have a range of project names
|
||||
|
||||
if ($signer) {
|
||||
$s = q("select site_project from site where site_url = '%s' limit 1",
|
||||
dbesc($signer[0]['hubloc_url'])
|
||||
);
|
||||
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
|
||||
$arr['comment_policy'] = 'authenticated';
|
||||
}
|
||||
else {
|
||||
$arr['comment_policy'] = 'contacts';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($AS->data['signed_data']) {
|
||||
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
||||
}
|
||||
|
||||
logger('FOF Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
|
||||
logger('FOF Activity recipient: ' . $channel['channel_portable_id'], LOGGER_DATA, LOG_DEBUG);
|
||||
logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG);
|
||||
|
||||
$result = self::process_delivery($arr['owner_xchan'],$AS, $arr, [ $channel['channel_portable_id'] ],false,false,true);
|
||||
$result = self::process_delivery($arr['owner_xchan'],$AS, $arr, [ $channel['channel_hash'] ],false,false,true);
|
||||
if ($result) {
|
||||
$ret = array_merge($ret, $result);
|
||||
}
|
||||
@@ -2027,7 +2106,7 @@ class Libzot {
|
||||
* @return boolean|int post_id
|
||||
*/
|
||||
|
||||
static function delete_imported_item($sender, $item, $uid, $relay) {
|
||||
static function delete_imported_item($sender, $act, $item, $uid, $relay) {
|
||||
|
||||
logger('invoked', LOGGER_DEBUG);
|
||||
|
||||
@@ -2035,36 +2114,39 @@ class Libzot {
|
||||
$item_found = false;
|
||||
$post_id = 0;
|
||||
|
||||
$r = q("select id, author_xchan, owner_xchan, source_xchan, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
|
||||
and mid = '%s' and uid = %d limit 1",
|
||||
if ($item['verb'] === 'Tombstone') {
|
||||
// The id of the deleted thing is the item mid (activity id)
|
||||
$mid = $item['mid'];
|
||||
}
|
||||
else {
|
||||
// The id is the object id if the type is Undo or Delete
|
||||
$mid = ((is_array($act->obj)) ? $act->obj['id'] : $act->obj);
|
||||
}
|
||||
|
||||
// we may have stored either the object id or the activity id if it was a response activity (like, dislike, etc.)
|
||||
|
||||
$r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
|
||||
and mid IN ('%s', '%s') and uid = %d limit 1",
|
||||
dbesc($sender),
|
||||
dbesc($sender),
|
||||
dbesc($sender),
|
||||
dbesc($item['mid']),
|
||||
dbesc($mid),
|
||||
dbesc(str_replace('/activity/','/item/',$mid)),
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
if($r[0]['author_xchan'] === $sender || $r[0]['owner_xchan'] === $sender || $r[0]['source_xchan'] === $sender)
|
||||
$ownership_valid = true;
|
||||
$stored = $r[0];
|
||||
|
||||
$post_id = $r[0]['id'];
|
||||
// we proved ownership in the sql query
|
||||
$ownership_valid = true;
|
||||
|
||||
$post_id = $stored['id'];
|
||||
$item_found = true;
|
||||
}
|
||||
else {
|
||||
|
||||
// perhaps the item is still in transit and the delete notification got here before the actual item did. Store it with the deleted flag set.
|
||||
// item_store() won't try to deliver any notifications or start delivery chains if this flag is set.
|
||||
// This means we won't end up with potentially even more delivery threads trying to push this delete notification.
|
||||
// But this will ensure that if the (undeleted) original post comes in at a later date, we'll reject it because it will have an older timestamp.
|
||||
|
||||
logger('delete received for non-existent item - storing item data.');
|
||||
|
||||
if($item['author_xchan'] === $sender || $item['owner_xchan'] === $sender || $item['source_xchan'] === $sender) {
|
||||
$ownership_valid = true;
|
||||
$item_result = item_store($item);
|
||||
$post_id = $item_result['item_id'];
|
||||
}
|
||||
// this will fail with an ownership issue, so explain the real reason
|
||||
logger('delete received for non-existent item or not owned by sender - ignoring.');
|
||||
}
|
||||
|
||||
if($ownership_valid === false) {
|
||||
@@ -2072,8 +2154,27 @@ class Libzot {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($stored['resource_type'] === 'event') {
|
||||
$i = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($stored['resource_id']),
|
||||
intval($uid)
|
||||
);
|
||||
if ($i) {
|
||||
if ($i[0]['event_xchan'] === $sender) {
|
||||
q("delete from event where event_hash = '%s' and uid = %d",
|
||||
dbesc($stored['resource_id']),
|
||||
intval($uid)
|
||||
);
|
||||
}
|
||||
else {
|
||||
logger('delete linked event: not owner');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($item_found) {
|
||||
if(intval($r[0]['item_deleted'])) {
|
||||
if(intval($stored['item_deleted'])) {
|
||||
logger('delete_imported_item: item was already deleted');
|
||||
if(! $relay)
|
||||
return false;
|
||||
@@ -2085,10 +2186,10 @@ class Libzot {
|
||||
// back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing
|
||||
// this information from the metadata should have no other discernible impact.
|
||||
|
||||
if (($r[0]['id'] != $r[0]['parent']) && intval($r[0]['item_origin'])) {
|
||||
if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) {
|
||||
q("update item set item_origin = 0 where id = %d and uid = %d",
|
||||
intval($r[0]['id']),
|
||||
intval($r[0]['uid'])
|
||||
intval($stored['id']),
|
||||
intval($stored['uid'])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2117,7 +2218,7 @@ class Libzot {
|
||||
|
||||
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
|
||||
|
||||
$r = q("select * from channel where channel_portable_id = '%s' limit 1",
|
||||
$r = q("select * from channel where channel_hash = '%s' limit 1",
|
||||
dbesc($d['hash'])
|
||||
);
|
||||
|
||||
@@ -2194,7 +2295,7 @@ class Libzot {
|
||||
*
|
||||
* @see import_directory_profile()
|
||||
*
|
||||
* @param string $sender
|
||||
* @param string $sender
|
||||
* @param array $arr
|
||||
* @param array $deliveries (unused)
|
||||
* @return void
|
||||
@@ -2215,7 +2316,7 @@ class Libzot {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param string $sender
|
||||
* @param string $sender
|
||||
* @param array $arr
|
||||
* @param array $deliveries (unused) deliveries is irrelevant
|
||||
* @return void
|
||||
@@ -2272,7 +2373,7 @@ class Libzot {
|
||||
|
||||
$loc = $locations[0];
|
||||
|
||||
$r = q("select * from channel where channel_portable_id = '%s' limit 1",
|
||||
$r = q("select * from channel where channel_hash = '%s' limit 1",
|
||||
dbesc($sender_hash)
|
||||
);
|
||||
|
||||
@@ -2280,7 +2381,7 @@ class Libzot {
|
||||
return;
|
||||
|
||||
if($loc['url'] !== z_root()) {
|
||||
$x = q("update channel set channel_moved = '%s' where channel_portable_id = '%s' limit 1",
|
||||
$x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1",
|
||||
dbesc($loc['url']),
|
||||
dbesc($sender_hash)
|
||||
);
|
||||
@@ -2314,7 +2415,7 @@ class Libzot {
|
||||
static function encode_locations($channel) {
|
||||
$ret = [];
|
||||
|
||||
$x = self::get_hublocs($channel['channel_portable_id']);
|
||||
$x = self::get_hublocs($channel['channel_hash']);
|
||||
|
||||
if($x && count($x)) {
|
||||
foreach($x as $hub) {
|
||||
@@ -2662,13 +2763,13 @@ class Libzot {
|
||||
$r = null;
|
||||
|
||||
if(strlen($zhash)) {
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
where channel_portable_id = '%s' limit 1",
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
where channel_hash = '%s' limit 1",
|
||||
dbesc($zhash)
|
||||
);
|
||||
}
|
||||
elseif(strlen($zguid) && strlen($zguid_sig)) {
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
|
||||
dbesc($zguid),
|
||||
dbesc($zguid_sig)
|
||||
@@ -2676,7 +2777,7 @@ class Libzot {
|
||||
}
|
||||
elseif(strlen($zaddr)) {
|
||||
if(strpos($zaddr,'[system]') === false) { /* normal address lookup */
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1",
|
||||
dbesc($zaddr),
|
||||
dbesc($zaddr)
|
||||
@@ -2696,10 +2797,10 @@ class Libzot {
|
||||
*
|
||||
*/
|
||||
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
where channel_system = 1 order by channel_id limit 1");
|
||||
if(! $r) {
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
where channel_removed = 0 order by channel_id limit 1");
|
||||
}
|
||||
}
|
||||
@@ -2764,7 +2865,7 @@ class Libzot {
|
||||
|
||||
$profile['description'] = $p[0]['pdesc'];
|
||||
$profile['birthday'] = $p[0]['dob'];
|
||||
if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== ''))
|
||||
if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],'UTC')) !== ''))
|
||||
$profile['next_birthday'] = $bd;
|
||||
|
||||
if($age = age($p[0]['dob'],$e['channel_timezone'],''))
|
||||
@@ -2818,7 +2919,7 @@ class Libzot {
|
||||
];
|
||||
|
||||
$ret['channel_role'] = get_pconfig($e['channel_id'],'system','permissions_role','custom');
|
||||
$ret['protocols'] = [ 'zot', 'zot6' ];
|
||||
$ret['protocols'] = [ 'zot6', 'zot' ];
|
||||
$ret['searchable'] = $searchable;
|
||||
$ret['adult_content'] = $adult_channel;
|
||||
$ret['public_forum'] = $public_forum;
|
||||
@@ -3096,4 +3197,26 @@ class Libzot {
|
||||
return(($x) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
static public function zot_record_preferred($arr, $check = 'hubloc_network') {
|
||||
|
||||
if(! $arr) {
|
||||
return $arr;
|
||||
}
|
||||
|
||||
foreach($arr as $v) {
|
||||
if($v[$check] === 'zot6') {
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
foreach($arr as $v) {
|
||||
if($v[$check] === 'zot') {
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $arr[0];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
use Zotlabs\Lib\Webfinger;
|
||||
|
||||
require_once('include/permissions.php');
|
||||
|
||||
@@ -307,9 +309,9 @@ class Libzotdir {
|
||||
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
|
||||
$success = false;
|
||||
|
||||
$href = \Zotlabs\Lib\Webfinger::zot_url(punify($url));
|
||||
$href = Webfinger::zot_url(punify($ud['ud_addr']));
|
||||
if($href) {
|
||||
$zf = \Zotlabs\Lib\Zotfinger::exec($href);
|
||||
$zf = Zotfinger::exec($href);
|
||||
}
|
||||
if(is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
|
||||
$xc = Libzot::import_xchan($zf['data'], 0, $ud);
|
||||
@@ -339,7 +341,7 @@ class Libzotdir {
|
||||
|
||||
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, channel_portable_id, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1",
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
@@ -348,6 +350,7 @@ class Libzotdir {
|
||||
|
||||
if ($p) {
|
||||
$hash = $p[0]['channel_hash'];
|
||||
$legacy_hash = $p[0]['channel_portable_id'];
|
||||
|
||||
$profile['description'] = $p[0]['pdesc'];
|
||||
$profile['birthday'] = $p[0]['dob'];
|
||||
@@ -381,14 +384,15 @@ class Libzotdir {
|
||||
|
||||
logger('hidden: ' . $hidden);
|
||||
|
||||
$r = q("select xchan_hidden from xchan where xchan_hash = '%s' limit 1",
|
||||
$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'",
|
||||
$r = q("update xchan set xchan_hidden = %d where xchan_hash in ('%s', '%s')",
|
||||
intval($hidden),
|
||||
dbesc($p[0]['channel_hash'])
|
||||
dbesc($hash),
|
||||
dbesc($legacy_hash)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -402,11 +406,13 @@ class Libzotdir {
|
||||
}
|
||||
else {
|
||||
// they may have made it private
|
||||
$r = q("delete from xprof where xprof_hash = '%s'",
|
||||
dbesc($hash)
|
||||
q("delete from xprof where xprof_hash in ('%s', '%s')",
|
||||
dbesc($hash),
|
||||
dbesc($legacy_hash)
|
||||
);
|
||||
$r = q("delete from xtag where xtag_hash = '%s'",
|
||||
dbesc($hash)
|
||||
q("delete from xtag where xtag_hash in ('%s', '%s')",
|
||||
dbesc($hash),
|
||||
dbesc($legacy_hash)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -651,4 +657,4 @@ class Libzotdir {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class MessageFilter {
|
||||
|
||||
$lang = null;
|
||||
|
||||
if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false)) {
|
||||
if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false) || (strpos($incl,'lang!=') !== false) || (strpos($excl,'lang!=') !== false)) {
|
||||
$lang = detect_language($text);
|
||||
}
|
||||
|
||||
@@ -39,10 +39,17 @@ class MessageFilter {
|
||||
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
return false;
|
||||
}
|
||||
elseif(substr($word,0,1) === '$' && $tags) {
|
||||
foreach($tags as $t)
|
||||
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
return false;
|
||||
}
|
||||
elseif((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;
|
||||
}
|
||||
@@ -60,10 +67,17 @@ class MessageFilter {
|
||||
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
return true;
|
||||
}
|
||||
elseif(substr($word,0,1) === '$' && $tags) {
|
||||
foreach($tags as $t)
|
||||
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
return true;
|
||||
}
|
||||
elseif((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;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
define ( 'NWIKI_ITEM_RESOURCE_TYPE', 'nwiki' );
|
||||
|
||||
class NativeWiki {
|
||||
@@ -71,7 +73,7 @@ class NativeWiki {
|
||||
$arr['item_thread_top'] = 1;
|
||||
$arr['item_private'] = intval($acl->is_private());
|
||||
$arr['verb'] = ACTIVITY_CREATE;
|
||||
$arr['obj_type'] = ACTIVITY_OBJ_WIKI;
|
||||
$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);
|
||||
@@ -178,7 +180,7 @@ class NativeWiki {
|
||||
foreach($sync_item as $w) {
|
||||
$pkt[] = encode_item($w,true);
|
||||
}
|
||||
build_sync_packet($uid,array('wiki' => $pkt));
|
||||
Libsync::build_sync_packet($uid,array('wiki' => $pkt));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +193,7 @@ class NativeWiki {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
else {
|
||||
$drop = drop_item($item['id'], false, DROPITEM_NORMAL, true);
|
||||
$drop = drop_item($item['id'], false, DROPITEM_NORMAL);
|
||||
}
|
||||
|
||||
info( t('Wiki files deleted successfully'));
|
||||
|
||||
@@ -530,8 +530,11 @@ class NativeWikiPage {
|
||||
foreach ($match[1] as $m) {
|
||||
// TODO: Why do we need to double urlencode for this to work?
|
||||
//$pageURLs[] = urlencode(urlencode(escape_tags($m)));
|
||||
$pageURLs[] = Zlib\NativeWiki::name_encode(escape_tags($m));
|
||||
$pages[] = $m;
|
||||
$titleUri = explode('|',$m);
|
||||
$page = $titleUri[0] ?? '';
|
||||
$title = $titleUri[1] ?? $page;
|
||||
$pageURLs[] = Zlib\NativeWiki::name_encode(escape_tags($page));
|
||||
$pages[] = $title;
|
||||
}
|
||||
$idx = 0;
|
||||
while(strpos($s,'[[') !== false) {
|
||||
|
||||
@@ -116,7 +116,7 @@ class Queue {
|
||||
dbesc($arr['hash']),
|
||||
intval($arr['account_id']),
|
||||
intval($arr['channel_id']),
|
||||
dbesc(($arr['driver']) ? $arr['driver'] : 'zot'),
|
||||
dbesc(($arr['driver']) ? $arr['driver'] : 'zot6'),
|
||||
dbesc($arr['posturl']),
|
||||
intval(1),
|
||||
intval(($arr['priority']) ? $arr['priority'] : 0),
|
||||
@@ -250,7 +250,7 @@ class Queue {
|
||||
$host_crypto = null;
|
||||
|
||||
if($channel && $base) {
|
||||
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1",
|
||||
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_sitekey != '' order by hubloc_id desc limit 1",
|
||||
dbesc($base)
|
||||
);
|
||||
if($h) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Activity;
|
||||
|
||||
class Share {
|
||||
|
||||
@@ -54,7 +55,7 @@ class Share {
|
||||
if(! $this->item)
|
||||
return $obj;
|
||||
|
||||
$obj['asld'] = $this->item['mid'];
|
||||
$obj['asld'] = Activity::fetch_item( [ 'id' => $this->item['mid'] ] );
|
||||
$obj['type'] = $this->item['obj_type'];
|
||||
$obj['id'] = $this->item['mid'];
|
||||
$obj['content'] = $this->item['body'];
|
||||
@@ -127,12 +128,12 @@ class Share {
|
||||
"' profile='" . $this->item['author']['xchan_url'] .
|
||||
"' avatar='" . $this->item['author']['xchan_photo_s'] .
|
||||
"' link='" . $this->item['plink'] .
|
||||
"' auth='" . (($this->item['author']['network'] === 'zot') ? 'true' : 'false') .
|
||||
"' auth='" . ((in_array($this->item['author']['xchan_network'], ['zot6', 'zot'])) ? 'true' : 'false') .
|
||||
"' posted='" . $this->item['created'] .
|
||||
"' message_id='" . $this->item['mid'] .
|
||||
"']";
|
||||
if($this->item['title'])
|
||||
$bb .= '[b]'.$this->item['title'].'[/b]'."\r\n";
|
||||
$bb .= '[h3][b]'.$this->item['title'].'[/b][/h3]'."\r\n";
|
||||
$bb .= (($is_photo) ? $photo_bb . "\r\n" . $this->item['body'] : $this->item['body']);
|
||||
$bb .= "[/share]";
|
||||
}
|
||||
|
||||
150
Zotlabs/Lib/SvgSanitizer.php
Normal file
150
Zotlabs/Lib/SvgSanitizer.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
use DomDocument;
|
||||
|
||||
/**
|
||||
* SVGSantiizer
|
||||
*
|
||||
* Whitelist-based PHP SVG sanitizer.
|
||||
*
|
||||
* @link https://github.com/alister-/SVG-Sanitizer}
|
||||
* @author Alister Norris
|
||||
* @copyright Copyright (c) 2013 Alister Norris
|
||||
* @license http://opensource.org/licenses/mit-license.php The MIT License
|
||||
* @package svgsanitizer
|
||||
*/
|
||||
|
||||
class SvgSanitizer {
|
||||
|
||||
private $xmlDoc; // PHP XML DOMDocument
|
||||
|
||||
private $removedattrs = [];
|
||||
|
||||
private static $allowed_functions = [ 'matrix', 'url', 'translate', 'rgb' ];
|
||||
|
||||
// defines the whitelist of elements and attributes allowed.
|
||||
private static $whitelist = [
|
||||
'a' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ],
|
||||
'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'clipPath' => [ 'class', 'clipPathUnits', 'id' ],
|
||||
'defs' => [ ],
|
||||
'style' => [ 'type' ],
|
||||
'desc' => [ ],
|
||||
'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ],
|
||||
'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ],
|
||||
'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ],
|
||||
'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ],
|
||||
'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ],
|
||||
'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ],
|
||||
'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ],
|
||||
'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ],
|
||||
'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ],
|
||||
'metadata' => [ 'class', 'id' ],
|
||||
'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ],
|
||||
'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ],
|
||||
'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ],
|
||||
'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ],
|
||||
'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ],
|
||||
'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ],
|
||||
'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ],
|
||||
'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ],
|
||||
'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ],
|
||||
'title' => [ ],
|
||||
'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ],
|
||||
'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ],
|
||||
];
|
||||
|
||||
function __construct() {
|
||||
$this->xmlDoc = new DOMDocument('1.0','UTF-8');
|
||||
$this->xmlDoc->preserveWhiteSpace = false;
|
||||
libxml_use_internal_errors(true);
|
||||
}
|
||||
|
||||
// load XML SVG
|
||||
function load($file) {
|
||||
$this->xmlDoc->load($file);
|
||||
}
|
||||
|
||||
function loadXML($str) {
|
||||
if (! $this->xmlDoc->loadXML($str)) {
|
||||
logger('loadxml: ' . print_r(libxml_get_errors(),true), LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function sanitize()
|
||||
{
|
||||
// all elements in xml doc
|
||||
$allElements = $this->xmlDoc->getElementsByTagName('*');
|
||||
|
||||
// loop through all elements
|
||||
for($i = 0; $i < $allElements->length; $i++)
|
||||
{
|
||||
$this->removedattrs = [];
|
||||
|
||||
$currentNode = $allElements->item($i);
|
||||
|
||||
// logger('current_node: ' . print_r($currentNode,true));
|
||||
|
||||
// array of allowed attributes in specific element
|
||||
$whitelist_attr_arr = self::$whitelist[$currentNode->tagName];
|
||||
|
||||
// does element exist in whitelist?
|
||||
if(isset($whitelist_attr_arr)) {
|
||||
$total = $currentNode->attributes->length;
|
||||
|
||||
for($x = 0; $x < $total; $x++) {
|
||||
|
||||
// get attributes name
|
||||
$attrName = $currentNode->attributes->item($x)->nodeName;
|
||||
|
||||
// logger('checking: ' . print_r($currentNode->attributes->item($x),true));
|
||||
$matches = false;
|
||||
|
||||
// check if attribute isn't in whitelist
|
||||
if(! in_array($attrName, $whitelist_attr_arr)) {
|
||||
$this->removedattrs[] = $attrName;
|
||||
}
|
||||
// check for disallowed functions
|
||||
elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/',
|
||||
$currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) {
|
||||
if ($attrName === 'text') {
|
||||
continue;
|
||||
}
|
||||
foreach ($matches as $match) {
|
||||
if(! in_array($match[1],self::$allowed_functions)) {
|
||||
logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG);
|
||||
$this->removedattrs[] = $attrName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->removedattrs) {
|
||||
foreach ($this->removedattrs as $attr) {
|
||||
$currentNode->removeAttribute($attr);
|
||||
logger('removed: ' . $attr, LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// else remove element
|
||||
else {
|
||||
logger('remove_node: ' . print_r($currentNode,true));
|
||||
$currentNode->parentNode->removeChild($currentNode);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function saveSVG() {
|
||||
$this->xmlDoc->formatOutput = true;
|
||||
return($this->xmlDoc->saveXML());
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,14 @@ namespace Zotlabs\Lib;
|
||||
class System {
|
||||
|
||||
static public function get_platform_name() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system']))
|
||||
return \App::$config['system']['platform_name'];
|
||||
return PLATFORM_NAME;
|
||||
static $platform_name = '';
|
||||
if(empty($platform_name)) {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system']))
|
||||
$platform_name = \App::$config['system']['platform_name'];
|
||||
else
|
||||
$platform_name = PLATFORM_NAME;
|
||||
}
|
||||
return $platform_name;
|
||||
}
|
||||
|
||||
static public function get_site_name() {
|
||||
|
||||
@@ -38,6 +38,7 @@ class ThreadItem {
|
||||
|
||||
$this->data = $data;
|
||||
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
|
||||
$this->threaded = get_config('system','thread_allow');
|
||||
|
||||
$observer = \App::get_observer();
|
||||
|
||||
@@ -77,7 +78,7 @@ class ThreadItem {
|
||||
*/
|
||||
|
||||
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
|
||||
|
||||
|
||||
$result = array();
|
||||
|
||||
$item = $this->get_data();
|
||||
@@ -94,10 +95,10 @@ class ThreadItem {
|
||||
$total_children = $this->count_descendants();
|
||||
$unseen_comments = (($item['real_uid']) ? 0 : $this->count_unseen_descendants());
|
||||
|
||||
$conv = $this->get_conversation();
|
||||
$conv = $this->get_conversation();
|
||||
$observer = $conv->get_observer();
|
||||
|
||||
$lock = ((($item['item_private'] == 1) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|
||||
$lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|
||||
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
|
||||
? t('Private Message')
|
||||
: false);
|
||||
@@ -109,10 +110,10 @@ class ThreadItem {
|
||||
$shareable = true;
|
||||
|
||||
$privacy_warning = false;
|
||||
if(($item['item_private'] == 1) && ($item['owner']['xchan_network'] === 'activitypub')) {
|
||||
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
|
||||
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
|
||||
|
||||
if(! in_array($observer['xchan_url'], $recips['to']))
|
||||
if(! is_array($recips['to']) || ! in_array($observer['xchan_url'], $recips['to']))
|
||||
$privacy_warning = true;
|
||||
}
|
||||
|
||||
@@ -149,9 +150,11 @@ class ThreadItem {
|
||||
$edpost = false;
|
||||
|
||||
|
||||
if($observer['xchan_hash'] == $this->get_data_value('author_xchan')
|
||||
if($observer && $observer['xchan_hash']
|
||||
&& ($observer['xchan_hash'] == $this->get_data_value('author_xchan')
|
||||
|| $observer['xchan_hash'] == $this->get_data_value('owner_xchan')
|
||||
|| $this->get_data_value('uid') == local_channel())
|
||||
|| $observer['xchan_hash'] == $this->get_data_value('source_xchan')
|
||||
|| $this->get_data_value('uid') == local_channel()))
|
||||
$dropping = true;
|
||||
|
||||
|
||||
@@ -203,6 +206,10 @@ class ThreadItem {
|
||||
}
|
||||
}
|
||||
|
||||
if($item['obj_type'] === 'Question') {
|
||||
$response_verbs[] = 'answer';
|
||||
}
|
||||
|
||||
$consensus = (intval($item['item_consensus']) ? true : false);
|
||||
if($consensus) {
|
||||
$response_verbs[] = 'agree';
|
||||
@@ -280,12 +287,16 @@ class ThreadItem {
|
||||
|
||||
$settings = '';
|
||||
|
||||
$tagger = [];
|
||||
|
||||
// FIXME - check this permission
|
||||
if($conv->get_profile_owner() == local_channel()) {
|
||||
/* disable until we agree on how to implemnt this in zot6/activitypub
|
||||
$tagger = array(
|
||||
'tagit' => t("Add Tag"),
|
||||
'classtagger' => "",
|
||||
);
|
||||
*/
|
||||
|
||||
$settings = t('Conversation Tools');
|
||||
}
|
||||
@@ -305,6 +316,7 @@ class ThreadItem {
|
||||
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"));
|
||||
}
|
||||
|
||||
if ($shareable) {
|
||||
@@ -331,7 +343,6 @@ class ThreadItem {
|
||||
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);
|
||||
@@ -345,12 +356,8 @@ class ThreadItem {
|
||||
$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('%d unseen',$unseen_comments) : '');
|
||||
$list_unseen_txt = (($unseen_comments) ? sprintf( t('%d unseen'),$unseen_comments) : '');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$children = $this->get_children();
|
||||
|
||||
$has_tags = (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false);
|
||||
@@ -359,11 +366,28 @@ class ThreadItem {
|
||||
call_hooks('dropdown_extras',$dropdown_extras_arr);
|
||||
$dropdown_extras = $dropdown_extras_arr['dropdown_extras'];
|
||||
|
||||
$midb64 = 'b64.' . base64url_encode($item['mid']);
|
||||
$mids = [ $midb64 ];
|
||||
$response_mids = [];
|
||||
foreach($response_verbs as $v) {
|
||||
if(isset($conv_responses[$v]['mids'][$item['mid']])) {
|
||||
$response_mids = array_merge($response_mids, $conv_responses[$v]['mids'][$item['mid']]);
|
||||
}
|
||||
}
|
||||
|
||||
$mids = array_merge($mids, $response_mids);
|
||||
$json_mids = json_encode($mids);
|
||||
|
||||
// Pinned item processing
|
||||
$allowed_type = (in_array($item['item_type'], get_config('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);
|
||||
|
||||
$tmp_item = array(
|
||||
'template' => $this->get_template(),
|
||||
'mode' => $mode,
|
||||
'item_type' => intval($item['item_type']),
|
||||
'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
|
||||
//'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
|
||||
'body' => $body['html'],
|
||||
'tags' => $body['tags'],
|
||||
'categories' => $body['categories'],
|
||||
@@ -372,14 +396,17 @@ class ThreadItem {
|
||||
'folders' => $body['folders'],
|
||||
'text' => strip_tags($body['html']),
|
||||
'id' => $this->get_id(),
|
||||
'mid' => $item['mid'],
|
||||
'mid' => $midb64,
|
||||
'mids' => $json_mids,
|
||||
'parent' => $item['parent'],
|
||||
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
||||
'isevent' => $isevent,
|
||||
'attend' => $attend,
|
||||
'consensus' => $consensus,
|
||||
'conlabels' => $conlabels,
|
||||
'canvote' => $canvote,
|
||||
'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, $item['author']['xchan_addr']),
|
||||
'olinktitle' => sprintf( t('View %s\'s profile - %s'), $this->get_owner_name(), $item['owner']['xchan_addr']),
|
||||
'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'],
|
||||
'viewthread' => $viewthread,
|
||||
'to' => t('to'),
|
||||
@@ -397,7 +424,7 @@ class ThreadItem {
|
||||
'sparkle' => $sparkle,
|
||||
'title' => $item['title'],
|
||||
'title_tosource' => get_pconfig($conv->get_profile_owner(),'system','title_tosource'),
|
||||
'ago' => relative_date($item['created']),
|
||||
//'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'),
|
||||
@@ -405,6 +432,7 @@ class ThreadItem {
|
||||
'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')):''),
|
||||
'lock' => $lock,
|
||||
'delayed' => $item['item_delayed'],
|
||||
'privacy_warning' => $privacy_warning,
|
||||
'verified' => $verified,
|
||||
'unverified' => $unverified,
|
||||
@@ -425,9 +453,11 @@ class ThreadItem {
|
||||
'has_tags' => $has_tags,
|
||||
'reactions' => $this->reactions,
|
||||
// Item toolbar buttons
|
||||
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
|
||||
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
|
||||
'like' => $like,
|
||||
'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
|
||||
'reply_to' => (((! $this->is_toplevel()) && feature_enabled($conv->get_profile_owner(),'reply_to')) ? $reply_to : ''),
|
||||
'top_hint' => t("Go to previous comment"),
|
||||
'share' => $share,
|
||||
'embed' => $embed,
|
||||
'rawmid' => $item['mid'],
|
||||
@@ -436,13 +466,15 @@ class ThreadItem {
|
||||
'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 : ''),
|
||||
'pinned' => ($pinned ? t('Pinned post') : ''),
|
||||
'pinnable' => (($this->is_toplevel() && local_channel() && $item['owner_xchan'] == $observer['xchan_hash'] && $allowed_type && $item['item_private'] == 0 && $item['item_delayed'] == 0) ? '1' : ''),
|
||||
'pinme' => ($pinned ? t('Unpin from the top') : t('Pin to the top')),
|
||||
'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,
|
||||
'dropdown_extras' => $dropdown_extras,
|
||||
// end toolbar buttons
|
||||
|
||||
'unseen_comments' => $unseen_comments,
|
||||
'comment_count' => $total_children,
|
||||
'comment_count_txt' => $comment_count_txt,
|
||||
@@ -463,13 +495,13 @@ class ThreadItem {
|
||||
'modal_dismiss' => t('Close'),
|
||||
'showlike' => $showlike,
|
||||
'showdislike' => $showdislike,
|
||||
'comment' => $this->get_comment_box($indent),
|
||||
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box($indent)),
|
||||
'previewing' => ($conv->is_preview() ? true : false ),
|
||||
'preview_lbl' => t('This is an unsaved preview'),
|
||||
'wait' => t('Please wait'),
|
||||
'submid' => str_replace(['+','='], ['',''], base64_encode($item['mid'])),
|
||||
'thread_level' => $thread_level,
|
||||
'settings' => $settings
|
||||
'settings' => $settings,
|
||||
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? 'b64.' . base64url_encode($item['thr_parent']) : '')
|
||||
);
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
@@ -777,8 +809,6 @@ class ThreadItem {
|
||||
call_hooks('comment_buttons',$arr);
|
||||
$comment_buttons = $arr['comment_buttons'];
|
||||
|
||||
$feature_auto_save_draft = ((feature_enabled($conv->get_profile_owner(), 'auto_save_draft')) ? "true" : "false");
|
||||
|
||||
$comment_box = replace_macros($template,array(
|
||||
'$return_path' => '',
|
||||
'$threaded' => $this->is_threaded(),
|
||||
@@ -813,8 +843,7 @@ class ThreadItem {
|
||||
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
|
||||
'$anonname' => [ 'anonname', t('Your full name (required)') ],
|
||||
'$anonmail' => [ 'anonmail', t('Your email address (required)') ],
|
||||
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ],
|
||||
'$auto_save_draft' => $feature_auto_save_draft,
|
||||
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
|
||||
));
|
||||
|
||||
return $comment_box;
|
||||
@@ -865,8 +894,4 @@ class ThreadItem {
|
||||
return $this->visiting;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class ThreadStream {
|
||||
private $preview = false;
|
||||
private $prepared_item = '';
|
||||
public $reload = '';
|
||||
private $cipher = 'aes256';
|
||||
private $cipher = 'AES-128-CCM';
|
||||
|
||||
// $prepared_item is for use by alternate conversation structures such as photos
|
||||
// wherein we've already prepared a top level item which doesn't look anything like
|
||||
|
||||
@@ -106,4 +106,4 @@ class Webfinger {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
|
||||
class ZotURL {
|
||||
@@ -66,7 +66,7 @@ class ZotURL {
|
||||
|
||||
}
|
||||
|
||||
static public function is_zoturl($s) {
|
||||
static public function is_zoturl($url) {
|
||||
|
||||
if(strpos($url,'x-zot:') === 0) {
|
||||
return true;
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
class Zotfinger {
|
||||
|
||||
static function exec($resource,$channel = null) {
|
||||
static function exec($resource,$channel = null, $verify = true) {
|
||||
|
||||
if(! $resource) {
|
||||
return false;
|
||||
@@ -41,8 +41,9 @@ class Zotfinger {
|
||||
logger('fetch: ' . print_r($x,true));
|
||||
|
||||
if($x['success']) {
|
||||
|
||||
$result['signature'] = HTTPSig::verify($x);
|
||||
if ($verify) {
|
||||
$result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6');
|
||||
}
|
||||
|
||||
$result['data'] = json_decode($x['body'],true);
|
||||
|
||||
@@ -60,4 +61,4 @@ class Zotfinger {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
// $type =
|
||||
// 'm' => autocomplete private mail recipient (checks post_mail permission)
|
||||
// 'm' => autocomplete private mail recipient (checks post_mail permission and displays only zot, diaspora, friendica-over-diaspora xchan_network xchan's)
|
||||
// 'a' => autocomplete connections (mod_connections, mod_poke, mod_sources, mod_photos)
|
||||
// 'x' => nav search bar autocomplete (match any xchan)
|
||||
// $_REQUEST['query'] contains autocomplete search text.
|
||||
@@ -166,7 +166,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
if($extra_channels) {
|
||||
foreach($extra_channels as $channel) {
|
||||
if(perm_is_allowed(intval($channel), get_observer_hash(),'view_contacts')) {
|
||||
if($extra_channel_sql)
|
||||
if($extra_channels_sql)
|
||||
$extra_channels_sql .= ',';
|
||||
$extra_channels_sql .= intval($channel);
|
||||
}
|
||||
@@ -286,6 +286,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d
|
||||
and xchan_deleted = 0
|
||||
and xchan_network IN ('zot', 'diaspora', 'friendica-over-diaspora')
|
||||
$sql_extra3
|
||||
ORDER BY xchan_name ASC ",
|
||||
intval(local_channel())
|
||||
|
||||
269
Zotlabs/Module/Activity.php
Normal file
269
Zotlabs/Module/Activity.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\IConfig;
|
||||
use Zotlabs\Lib\Enotify;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\Activity as ZlibActivity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\LDSignatures;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\ThreadListener;
|
||||
use App;
|
||||
|
||||
|
||||
class Activity extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
if (Libzot::is_zot_request()) {
|
||||
|
||||
$item_id = argv(1);
|
||||
if (! $item_id)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$portable_id = EMPTY_STR;
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 ";
|
||||
|
||||
$i = null;
|
||||
|
||||
// do we have the item (at all)?
|
||||
|
||||
$r = q("select * from item where mid = '%s' $item_normal limit 1",
|
||||
dbesc(z_root() . '/activity/' . $item_id)
|
||||
);
|
||||
|
||||
if (! $r) {
|
||||
http_status_exit(404,'Not found');
|
||||
}
|
||||
|
||||
// process an authenticated fetch
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
if($sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
$portable_id = $sigdata['portable_id'];
|
||||
observer_auth($portable_id);
|
||||
|
||||
// first see if we have a copy of this item's parent owned by the current signer
|
||||
// include xchans for all zot-like networks - these will have the same guid and public key
|
||||
|
||||
$x = q("select * from xchan where xchan_hash = '%s'",
|
||||
dbesc($sigdata['portable_id'])
|
||||
);
|
||||
|
||||
if ($x) {
|
||||
$xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
|
||||
dbesc($sigdata['portable_id']),
|
||||
dbesc($x[0]['xchan_guid']),
|
||||
dbesc($x[0]['xchan_pubkey'])
|
||||
);
|
||||
|
||||
if ($xchans) {
|
||||
$hashes = ids_to_querystr($xchans,'xchan_hash',true);
|
||||
$i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1",
|
||||
dbesc($r[0]['parent_mid'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
|
||||
// with a bias towards those items owned by channels on this site (item_wall = 1)
|
||||
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
if (! $i) {
|
||||
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
|
||||
dbesc($r[0]['parent_mid'])
|
||||
);
|
||||
}
|
||||
|
||||
if(! $i) {
|
||||
http_status_exit(403,'Forbidden');
|
||||
}
|
||||
|
||||
$parents_str = ids_to_querystr($i,'item_id');
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ",
|
||||
dbesc($parents_str)
|
||||
);
|
||||
|
||||
if(! $items) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
xchan_query($items,true);
|
||||
$items = fetch_post_tags($items,true);
|
||||
|
||||
$observer = App::get_observer();
|
||||
$parent = $items[0];
|
||||
$recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'],'activitypub','recips', []) : []);
|
||||
$to = (($recips && array_key_exists('to',$recips) && is_array($recips['to'])) ? $recips['to'] : null);
|
||||
$nitems = [];
|
||||
foreach($items as $i) {
|
||||
|
||||
$mids = [];
|
||||
|
||||
if(intval($i['item_private'])) {
|
||||
if(! $observer) {
|
||||
continue;
|
||||
}
|
||||
// ignore private reshare, possibly from hubzilla
|
||||
if($i['verb'] === 'Announce') {
|
||||
if(! in_array($i['thr_parent'],$mids)) {
|
||||
$mids[] = $i['thr_parent'];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// also ignore any children of the private reshares
|
||||
if(in_array($i['thr_parent'],$mids)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if((! $to) || (! in_array($observer['xchan_url'],$to))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
$nitems[] = $i;
|
||||
}
|
||||
|
||||
if(! $nitems)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$chan = channelx_by_n($nitems[0]['uid']);
|
||||
|
||||
if(! $chan)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
|
||||
http_status_exit(403, 'Forbidden');
|
||||
|
||||
$i = ZlibActivity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection');
|
||||
if($portable_id) {
|
||||
ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id);
|
||||
}
|
||||
|
||||
if(! $i)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$x = array_merge(['@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1',
|
||||
z_root() . ZOT_APSCHEMA_REV
|
||||
]], $i);
|
||||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/x-zot+json' ;
|
||||
$x['signature'] = LDSignatures::sign($x,$chan);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $ret;
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
if(ActivityStreams::is_as_request()) {
|
||||
|
||||
$item_id = argv(1);
|
||||
|
||||
if (! $item_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ob_authorise = false;
|
||||
$item_uid = 0;
|
||||
|
||||
$bear = ZlibActivity::token_from_request();
|
||||
if ($bear) {
|
||||
logger('bear: ' . $bear, LOGGER_DEBUG);
|
||||
$t = q("select item.uid, iconfig.v from iconfig left join item on iid = item.id where cat = 'ocap' and item.uuid = '%s'",
|
||||
dbesc($item_id)
|
||||
);
|
||||
if ($t) {
|
||||
foreach ($t as $token) {
|
||||
if ($token['v'] === $bear) {
|
||||
$ob_authorize = true;
|
||||
$item_uid = $token['uid'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
|
||||
and item.item_delayed = 0 and item.item_blocked = 0 ";
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
$portable_id = $sigdata['portable_id'];
|
||||
if (! check_channelallowed($portable_id)) {
|
||||
http_status_exit(403, 'Permission denied');
|
||||
}
|
||||
if (! check_siteallowed($sigdata['signer'])) {
|
||||
http_status_exit(403, 'Permission denied');
|
||||
}
|
||||
observer_auth($portable_id);
|
||||
}
|
||||
|
||||
// if passed an owner_id of 0 to item_permissions_sql(), we force "guest access" or observer checking
|
||||
// Give ocap tokens priority
|
||||
|
||||
if ($ob_authorize) {
|
||||
$sql_extra = " and item.uid = " . intval($token['uid']) . " ";
|
||||
}
|
||||
else {
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
}
|
||||
|
||||
$r = q("select * from item where uuid = '%s' $item_normal $sql_extra limit 1",
|
||||
dbesc($item_id)
|
||||
);
|
||||
|
||||
if (! $r) {
|
||||
$r = q("select * from item where uuid = '%s' $item_normal limit 1",
|
||||
dbesc($item_id)
|
||||
);
|
||||
if($r) {
|
||||
http_status_exit(403, 'Forbidden');
|
||||
}
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
xchan_query($r,true);
|
||||
$items = fetch_post_tags($r,false);
|
||||
|
||||
$channel = channelx_by_n($items[0]['uid']);
|
||||
|
||||
$x = array_merge( ['@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1',
|
||||
z_root() . ZOT_APSCHEMA_REV
|
||||
]], ZlibActivity::encode_activity($items[0],true));
|
||||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
|
||||
$x['signature'] = LDSignatures::sign($x,$channel);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $ret;
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
goaway(z_root() . '/item/' . argv(1));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
use App;
|
||||
use \Zotlabs\Storage\GitRepo;
|
||||
use \Michelf\MarkdownExtra;
|
||||
|
||||
@@ -17,7 +18,7 @@ class Addons {
|
||||
@include_once("addon/" . argv(2) . "/" . argv(2) . ".php");
|
||||
if(function_exists(argv(2).'_plugin_admin_post')) {
|
||||
$func = argv(2) . '_plugin_admin_post';
|
||||
$func($a);
|
||||
$func();
|
||||
}
|
||||
|
||||
goaway(z_root() . '/admin/addons/' . argv(2) );
|
||||
@@ -253,14 +254,14 @@ class Addons {
|
||||
* Single plugin
|
||||
*/
|
||||
|
||||
if (\App::$argc == 3){
|
||||
$plugin = \App::$argv[2];
|
||||
if (App::$argc == 3){
|
||||
$plugin = App::$argv[2];
|
||||
if (!is_file("addon/$plugin/$plugin.php")){
|
||||
notice( t("Item not found.") );
|
||||
return '';
|
||||
}
|
||||
|
||||
$enabled = in_array($plugin,\App::$plugins);
|
||||
$enabled = in_array($plugin,App::$plugins);
|
||||
$info = get_plugin_info($plugin);
|
||||
$x = check_plugin_versions($info);
|
||||
|
||||
@@ -268,11 +269,11 @@ class Addons {
|
||||
|
||||
if($enabled && ! $x) {
|
||||
$enabled = false;
|
||||
$idz = array_search($plugin, \App::$plugins);
|
||||
$idz = array_search($plugin, App::$plugins);
|
||||
if ($idz !== false) {
|
||||
unset(\App::$plugins[$idz]);
|
||||
unset(App::$plugins[$idz]);
|
||||
uninstall_plugin($plugin);
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
}
|
||||
}
|
||||
$info['disabled'] = 1-intval($x);
|
||||
@@ -281,19 +282,19 @@ class Addons {
|
||||
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
|
||||
$pinstalled = false;
|
||||
// Toggle plugin status
|
||||
$idx = array_search($plugin, \App::$plugins);
|
||||
$idx = array_search($plugin, App::$plugins);
|
||||
if ($idx !== false){
|
||||
unset(\App::$plugins[$idx]);
|
||||
unset(App::$plugins[$idx]);
|
||||
uninstall_plugin($plugin);
|
||||
$pinstalled = false;
|
||||
info( sprintf( t("Plugin %s disabled."), $plugin ) );
|
||||
} else {
|
||||
\App::$plugins[] = $plugin;
|
||||
App::$plugins[] = $plugin;
|
||||
install_plugin($plugin);
|
||||
$pinstalled = true;
|
||||
info( sprintf( t("Plugin %s enabled."), $plugin ) );
|
||||
}
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
|
||||
if($pinstalled) {
|
||||
@require_once("addon/$plugin/$plugin.php");
|
||||
@@ -305,7 +306,7 @@ class Addons {
|
||||
|
||||
// display plugin details
|
||||
|
||||
if (in_array($plugin, \App::$plugins)){
|
||||
if (in_array($plugin, App::$plugins)){
|
||||
$status = 'on';
|
||||
$action = t('Disable');
|
||||
} else {
|
||||
@@ -331,7 +332,7 @@ class Addons {
|
||||
@require_once("addon/$plugin/$plugin.php");
|
||||
if(function_exists($plugin.'_plugin_admin')) {
|
||||
$func = $plugin.'_plugin_admin';
|
||||
$func($a, $admin_form);
|
||||
$func($admin_form);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,18 +381,18 @@ class Addons {
|
||||
|
||||
list($tmp, $id) = array_map('trim', explode('/', $file));
|
||||
$info = get_plugin_info($id);
|
||||
$enabled = in_array($id,\App::$plugins);
|
||||
$enabled = in_array($id,App::$plugins);
|
||||
$x = check_plugin_versions($info);
|
||||
|
||||
// disable plugins which are installed but incompatible versions
|
||||
|
||||
if($enabled && ! $x) {
|
||||
$enabled = false;
|
||||
$idz = array_search($id, \App::$plugins);
|
||||
$idz = array_search($id, App::$plugins);
|
||||
if ($idz !== false) {
|
||||
unset(\App::$plugins[$idz]);
|
||||
unset(App::$plugins[$idz]);
|
||||
uninstall_plugin($id);
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
}
|
||||
}
|
||||
$info['disabled'] = 1-intval($x);
|
||||
|
||||
@@ -19,7 +19,47 @@ class Dbsync {
|
||||
info( t('Update has been marked successful') . EOL);
|
||||
goaway(z_root() . '/admin/dbsync');
|
||||
}
|
||||
|
||||
if(argc() > 3 && intval(argv(3)) && argv(2) === 'verify') {
|
||||
|
||||
$s = '_' . intval(argv(3));
|
||||
$cls = '\\Zotlabs\Update\\' . $s ;
|
||||
if(class_exists($cls)) {
|
||||
$c = new $cls();
|
||||
if(method_exists($c,'verify')) {
|
||||
$retval = $c->verify();
|
||||
if($retval === UPDATE_FAILED) {
|
||||
$o .= sprintf( t('Verification of update %s failed. Check system logs.'), $s);
|
||||
}
|
||||
elseif($retval === UPDATE_SUCCESS) {
|
||||
$o .= sprintf( t('Update %s was successfully applied.'), $s);
|
||||
set_config('database',$s, 'success');
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Verifying update %s did not return a status. Unknown if it succeeded.'), $s);
|
||||
}
|
||||
else {
|
||||
$o .= sprintf( t('Update %s does not contain a verification function.'), $s );
|
||||
}
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Update function %s could not be found.'), $s);
|
||||
|
||||
return $o;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// remove the old style config if it exists
|
||||
del_config('database', 'update_r' . intval(argv(3)));
|
||||
set_config('database', '_' . intval(argv(3)), 'success');
|
||||
if(intval(get_config('system','db_version')) < intval(argv(3)))
|
||||
set_config('system','db_version',intval(argv(3)));
|
||||
info( t('Update has been marked successful') . EOL);
|
||||
goaway(z_root() . '/admin/dbsync');
|
||||
}
|
||||
|
||||
if(argc() > 2 && intval(argv(2))) {
|
||||
$x = intval(argv(2));
|
||||
$s = '_' . $x;
|
||||
@@ -28,14 +68,14 @@ class Dbsync {
|
||||
$c = new $cls();
|
||||
$retval = $c->run();
|
||||
if($retval === UPDATE_FAILED) {
|
||||
$o .= sprintf( t('Executing %s failed. Check system logs.'), $s);
|
||||
$o .= sprintf( t('Executing update procedure %s failed. Check system logs.'), $s);
|
||||
}
|
||||
elseif($retval === UPDATE_SUCCESS) {
|
||||
$o .= sprintf( t('Update %s was successfully applied.'), $s);
|
||||
set_config('database',$s, 'success');
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Update %s did not return a status. Unknown if it succeeded.'), $s);
|
||||
$o .= sprintf( t('Update %s did not return a status. It cannot be determined if it was successful.'), $s);
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Update function %s could not be found.'), $s);
|
||||
@@ -59,6 +99,7 @@ class Dbsync {
|
||||
'$banner' => t('Failed Updates'),
|
||||
'$desc' => '',
|
||||
'$mark' => t('Mark success (if update was manually applied)'),
|
||||
'$verify' => t('Attempt to verify this update if a verification procedure exists'),
|
||||
'$apply' => t('Attempt to execute this update step automatically'),
|
||||
'$failed' => $failed
|
||||
));
|
||||
|
||||
@@ -43,6 +43,12 @@ class Security {
|
||||
|
||||
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
|
||||
set_config('system','embed_deny',$be);
|
||||
|
||||
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
|
||||
set_config('system', 'thumbnail_security' , $thumbnail_security);
|
||||
|
||||
$inline_pdf = ((x($_POST,'inline_pdf')) ? intval($_POST['inline_pdf']) : 0);
|
||||
set_config('system', 'inline_pdf' , $inline_pdf);
|
||||
|
||||
$ts = ((x($_POST,'transport_security')) ? True : False);
|
||||
set_config('system','transport_security_header',$ts);
|
||||
@@ -86,7 +92,7 @@ class Security {
|
||||
$embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:");
|
||||
$embedhelp3 = t("https://youtube.com/<br />https://www.youtube.com/<br />https://youtu.be/<br />https://vimeo.com/<br />https://soundcloud.com/<br />");
|
||||
$embedhelp4 = t("All other embedded content will be filtered, <strong>unless</strong> embedded content from that site is explicitly blocked.");
|
||||
|
||||
|
||||
$t = get_markup_template('admin_security.tpl');
|
||||
return replace_macros($t, array(
|
||||
'$title' => t('Administration'),
|
||||
@@ -106,7 +112,9 @@ class Security {
|
||||
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
|
||||
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
|
||||
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
|
||||
|
||||
'$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
|
||||
'$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ],
|
||||
|
||||
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),
|
||||
|
||||
'$submit' => t('Submit')
|
||||
@@ -128,4 +136,4 @@ class Security {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,9 @@ class Site {
|
||||
$from_email = ((array_key_exists('from_email',$_POST) && trim($_POST['from_email'])) ? trim($_POST['from_email']) : 'Administrator@' . \App::get_hostname());
|
||||
$from_email_name = ((array_key_exists('from_email_name',$_POST) && trim($_POST['from_email_name'])) ? trim($_POST['from_email_name']) : \Zotlabs\Lib\System::get_site_name());
|
||||
|
||||
|
||||
$sse_enabled = ((x($_POST,'sse_enabled')) ? true : false);
|
||||
|
||||
$verifyssl = ((x($_POST,'verifyssl')) ? True : False);
|
||||
$proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['proxyuser'])) : '');
|
||||
$proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['proxy'])) : '');
|
||||
@@ -73,7 +76,6 @@ class Site {
|
||||
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
|
||||
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
|
||||
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
|
||||
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
|
||||
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
|
||||
$pub_incl = escape_tags(trim($_POST['pub_incl']));
|
||||
$pub_excl = escape_tags(trim($_POST['pub_excl']));
|
||||
@@ -100,7 +102,6 @@ class Site {
|
||||
set_config('system', 'from_email', $from_email);
|
||||
set_config('system', 'from_email_name' , $from_email_name);
|
||||
set_config('system', 'imagick_convert_path' , $imagick_path);
|
||||
set_config('system', 'thumbnail_security' , $thumbnail_security);
|
||||
set_config('system', 'default_permissions_role', $permissions_role);
|
||||
set_config('system', 'pubstream_incl',$pub_incl);
|
||||
set_config('system', 'pubstream_excl',$pub_excl);
|
||||
@@ -153,6 +154,9 @@ class Site {
|
||||
|
||||
set_config('system','no_community_page', $no_community_page);
|
||||
set_config('system','no_utf', $no_utf);
|
||||
|
||||
set_config('system','sse_enabled', $sse_enabled);
|
||||
|
||||
set_config('system','verifyssl', $verifyssl);
|
||||
set_config('system','proxyuser', $proxyuser);
|
||||
set_config('system','proxy', $proxy);
|
||||
@@ -333,6 +337,8 @@ class Site {
|
||||
|
||||
'$directory_server' => (($dir_choices) ? array('directory_server', t("Directory Server URL"), get_config('system','directory_server'), t("Default directory server"), $dir_choices) : null),
|
||||
|
||||
'$sse_enabled' => array('sse_enabled', t('Enable SSE Notifications'), get_config('system', 'sse_enabled', 0), t('If disabled, traditional polling will be used. Warning: this setting might not be suited for shared hosting')),
|
||||
|
||||
'$proxyuser' => array('proxyuser', t("Proxy user"), get_config('system','proxyuser'), ""),
|
||||
'$proxy' => array('proxy', t("Proxy URL"), get_config('system','proxy'), ""),
|
||||
'$timeout' => array('timeout', t("Network timeout"), (x(get_config('system','curl_timeout'))?get_config('system','curl_timeout'):60), t("Value is in seconds. Set to 0 for unlimited (not recommended).")),
|
||||
@@ -341,7 +347,6 @@ class Site {
|
||||
'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
|
||||
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
|
||||
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
|
||||
'$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")),
|
||||
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
|
||||
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
|
||||
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),
|
||||
|
||||
@@ -34,9 +34,9 @@ class Apporder extends \Zotlabs\Web\Controller {
|
||||
|
||||
foreach($syslist as $app) {
|
||||
if($l === 'nav_pinned_app') {
|
||||
$navbar_apps[] = Zlib\Apps::app_render($app,'nav-order');
|
||||
$navbar_apps[] = Zlib\Apps::app_render($app,'nav-order-pinned');
|
||||
}
|
||||
elseif(strpos($app['categories'],'nav_pinned_app') === false) {
|
||||
else {
|
||||
$nav_apps[] = Zlib\Apps::app_render($app,'nav-order');
|
||||
}
|
||||
}
|
||||
|
||||
66
Zotlabs/Module/Apschema.php
Normal file
66
Zotlabs/Module/Apschema.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
|
||||
class Apschema extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$base = z_root();
|
||||
|
||||
$arr = [
|
||||
'@context' => [
|
||||
'zot' => z_root() . '/apschema#',
|
||||
'id' => '@id',
|
||||
'type' => '@type',
|
||||
'commentPolicy' => 'as:commentPolicy',
|
||||
'meData' => 'zot:meData',
|
||||
'meDataType' => 'zot:meDataType',
|
||||
'meEncoding' => 'zot:meEncoding',
|
||||
'meAlgorithm' => 'zot:meAlgorithm',
|
||||
'meCreator' => 'zot:meCreator',
|
||||
'meSignatureValue' => 'zot:meSignatureValue',
|
||||
'locationAddress' => 'zot:locationAddress',
|
||||
'locationPrimary' => 'zot:locationPrimary',
|
||||
'locationDeleted' => 'zot:locationDeleted',
|
||||
'nomadicLocation' => 'zot:nomadicLocation',
|
||||
'nomadicHubs' => 'zot:nomadicHubs',
|
||||
'emojiReaction' => 'zot:emojiReaction',
|
||||
'expires' => 'zot:expires',
|
||||
'directMessage' => 'zot:directMessage',
|
||||
'schema' => 'http://schema.org#',
|
||||
'PropertyValue' => 'schema:PropertyValue',
|
||||
'value' => 'schema:value',
|
||||
|
||||
'magicEnv' => [
|
||||
'@id' => 'zot:magicEnv',
|
||||
'@type' => '@id'
|
||||
],
|
||||
|
||||
'nomadicLocations' => [
|
||||
'@id' => 'zot:nomadicLocations',
|
||||
'@type' => '@id'
|
||||
],
|
||||
|
||||
'ostatus' => 'http://ostatus.org#',
|
||||
'conversation' => 'ostatus:conversation',
|
||||
|
||||
'diaspora' => 'https://diasporafoundation.org/ns/',
|
||||
'guid' => 'diaspora:guid',
|
||||
|
||||
'Hashtag' => 'as:Hashtag'
|
||||
|
||||
]
|
||||
];
|
||||
|
||||
header('Content-Type: application/ld+json');
|
||||
echo json_encode($arr,JSON_UNESCAPED_SLASHES);
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -85,10 +85,9 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
|
||||
$mimetype = $itm[0]['mimetype'];
|
||||
|
||||
$summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
|
||||
$content = $itm[0]['body'];
|
||||
|
||||
|
||||
|
||||
$rp = 'articles/' . $channel['channel_address'];
|
||||
|
||||
$x = array(
|
||||
@@ -110,7 +109,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
'ptyp' => $itm[0]['type'],
|
||||
'mimeselect' => false,
|
||||
'mimetype' => $itm[0]['mimetype'],
|
||||
'body' => undo_post_tagging($content),
|
||||
'body' => $summary . undo_post_tagging($content),
|
||||
'post_id' => $post_id,
|
||||
'visitor' => true,
|
||||
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
||||
|
||||
@@ -9,6 +9,7 @@ use Zotlabs\Lib\PermissionDescription;
|
||||
require_once('include/channel.php');
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/acl_selectors.php');
|
||||
require_once('include/opengraph.php');
|
||||
|
||||
|
||||
class Articles extends Controller {
|
||||
@@ -148,7 +149,7 @@ class Articles extends Controller {
|
||||
}
|
||||
|
||||
$itemspage = get_pconfig(local_channel(),'system','itemspage');
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
|
||||
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
|
||||
|
||||
|
||||
@@ -192,7 +193,7 @@ class Articles extends Controller {
|
||||
|
||||
$parents_str = ids_to_querystr($r,'id');
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id
|
||||
$r = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE item.uid = %d $item_normal
|
||||
AND item.parent IN ( %s )
|
||||
@@ -200,15 +201,18 @@ class Articles extends Controller {
|
||||
intval(App::$profile['profile_uid']),
|
||||
dbesc($parents_str)
|
||||
);
|
||||
if($items) {
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
$items = conv_sort($items,'updated');
|
||||
}
|
||||
else
|
||||
$items = [];
|
||||
}
|
||||
|
||||
// Add Opengraph markup
|
||||
opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
|
||||
|
||||
$mode = 'articles';
|
||||
|
||||
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/datetime.php');
|
||||
@@ -9,15 +13,13 @@ require_once('include/items.php');
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
|
||||
class Cal extends \Zotlabs\Web\Controller {
|
||||
class Cal extends Controller {
|
||||
|
||||
function init() {
|
||||
if(observer_prohibited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$o = '';
|
||||
|
||||
if(argc() > 1) {
|
||||
$nick = argv(1);
|
||||
|
||||
@@ -25,19 +27,21 @@ class Cal extends \Zotlabs\Web\Controller {
|
||||
|
||||
$channelx = channelx_by_nick($nick);
|
||||
|
||||
if(! $channelx)
|
||||
if(! $channelx) {
|
||||
notice( t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
\App::$data['channel'] = $channelx;
|
||||
App::$data['channel'] = $channelx;
|
||||
|
||||
$observer = \App::get_observer();
|
||||
\App::$data['observer'] = $observer;
|
||||
$observer = App::get_observer();
|
||||
App::$data['observer'] = $observer;
|
||||
|
||||
$observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
|
||||
|
||||
head_set_icon(\App::$data['channel']['xchan_photo_s']);
|
||||
head_set_icon(App::$data['channel']['xchan_photo_s']);
|
||||
|
||||
\App::$page['htmlhead'] .= "<script> var profile_uid = " . ((\App::$data['channel']) ? \App::$data['channel']['channel_id'] : 0) . "; </script>" ;
|
||||
App::$page['htmlhead'] .= "<script> var profile_uid = " . ((App::$data['channel']) ? App::$data['channel']['channel_id'] : 0) . "; </script>" ;
|
||||
|
||||
}
|
||||
|
||||
@@ -52,18 +56,8 @@ class Cal extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = null;
|
||||
|
||||
if(argc() > 1) {
|
||||
$channel = channelx_by_nick(argv(1));
|
||||
}
|
||||
|
||||
|
||||
if(! $channel) {
|
||||
notice( t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = App::$data['channel'];
|
||||
|
||||
// since we don't currently have an event permission - use the stream permission
|
||||
|
||||
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) {
|
||||
@@ -72,287 +66,152 @@ class Cal extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
nav_set_selected('Calendar');
|
||||
|
||||
head_add_css('/library/fullcalendar/packages/core/main.min.css');
|
||||
head_add_css('/library/fullcalendar/packages/daygrid/main.min.css');
|
||||
head_add_css('cdav_calendar.css');
|
||||
|
||||
head_add_js('/library/fullcalendar/packages/core/main.min.js');
|
||||
head_add_js('/library/fullcalendar/packages/daygrid/main.min.js');
|
||||
|
||||
$sql_extra = permissions_sql($channel['channel_id'], get_observer_hash(), 'event');
|
||||
|
||||
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts') || App::$profile['hide_friends'])
|
||||
$sql_extra .= " and etype != 'birthday' ";
|
||||
|
||||
$sql_extra = permissions_sql($channel['channel_id'],get_observer_hash(),'event');
|
||||
|
||||
$first_day = feature_enabled($channel['channel_id'], 'events_cal_first_day');
|
||||
$first_day = feature_enabled($channel['channel_id'], 'cal_first_day');
|
||||
$first_day = (($first_day) ? $first_day : 0);
|
||||
|
||||
$htpl = get_markup_template('event_head.tpl');
|
||||
\App::$page['htmlhead'] .= replace_macros($htpl,array(
|
||||
'$baseurl' => z_root(),
|
||||
'$module_url' => '/cal/' . $channel['channel_address'],
|
||||
'$modparams' => 2,
|
||||
'$lang' => \App::$language,
|
||||
'$first_day' => $first_day
|
||||
));
|
||||
|
||||
$o = '';
|
||||
|
||||
$mode = 'view';
|
||||
$y = 0;
|
||||
$m = 0;
|
||||
$ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
|
||||
|
||||
// logger('args: ' . print_r(\App::$argv,true));
|
||||
|
||||
if(argc() > 3 && intval(argv(2)) && intval(argv(3))) {
|
||||
$mode = 'view';
|
||||
$y = intval(argv(2));
|
||||
$m = intval(argv(3));
|
||||
}
|
||||
if(argc() <= 3) {
|
||||
$mode = 'view';
|
||||
$event_id = argv(2);
|
||||
$start = '';
|
||||
$finish = '';
|
||||
|
||||
if (argv(2) === 'json') {
|
||||
if (x($_GET,'start')) $start = $_GET['start'];
|
||||
if (x($_GET,'end')) $finish = $_GET['end'];
|
||||
}
|
||||
|
||||
if($mode == 'view') {
|
||||
|
||||
/* edit/create form */
|
||||
if($event_id) {
|
||||
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($event_id),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if(count($r))
|
||||
$orig_event = $r[0];
|
||||
}
|
||||
|
||||
|
||||
// Passed parameters overrides anything found in the DB
|
||||
if(!x($orig_event))
|
||||
$orig_event = array();
|
||||
|
||||
|
||||
|
||||
$tz = date_default_timezone_get();
|
||||
if(x($orig_event))
|
||||
$tz = (($orig_event['adjust']) ? date_default_timezone_get() : 'UTC');
|
||||
|
||||
$syear = datetime_convert('UTC', $tz, $sdt, 'Y');
|
||||
$smonth = datetime_convert('UTC', $tz, $sdt, 'm');
|
||||
$sday = datetime_convert('UTC', $tz, $sdt, 'd');
|
||||
$shour = datetime_convert('UTC', $tz, $sdt, 'H');
|
||||
$sminute = datetime_convert('UTC', $tz, $sdt, 'i');
|
||||
|
||||
$stext = datetime_convert('UTC',$tz,$sdt);
|
||||
$stext = substr($stext,0,14) . "00:00";
|
||||
|
||||
$fyear = datetime_convert('UTC', $tz, $fdt, 'Y');
|
||||
$fmonth = datetime_convert('UTC', $tz, $fdt, 'm');
|
||||
$fday = datetime_convert('UTC', $tz, $fdt, 'd');
|
||||
$fhour = datetime_convert('UTC', $tz, $fdt, 'H');
|
||||
$fminute = datetime_convert('UTC', $tz, $fdt, 'i');
|
||||
|
||||
$ftext = datetime_convert('UTC',$tz,$fdt);
|
||||
$ftext = substr($ftext,0,14) . "00:00";
|
||||
|
||||
$type = ((x($orig_event)) ? $orig_event['etype'] : 'event');
|
||||
|
||||
$f = get_config('system','event_input_format');
|
||||
if(! $f)
|
||||
$f = 'ymd';
|
||||
|
||||
$catsenabled = feature_enabled($channel['channel_id'],'categories');
|
||||
|
||||
|
||||
$show_bd = perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts');
|
||||
if(! $show_bd) {
|
||||
$sql_extra .= " and event.etype != 'birthday' ";
|
||||
}
|
||||
|
||||
|
||||
$category = '';
|
||||
|
||||
$thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y');
|
||||
$thismonth = datetime_convert('UTC',date_default_timezone_get(),'now','m');
|
||||
if(! $y)
|
||||
$y = intval($thisyear);
|
||||
if(! $m)
|
||||
$m = intval($thismonth);
|
||||
|
||||
// Put some limits on dates. The PHP date functions don't seem to do so well before 1900.
|
||||
// An upper limit was chosen to keep search engines from exploring links millions of years in the future.
|
||||
|
||||
if($y < 1901)
|
||||
$y = 1900;
|
||||
if($y > 2099)
|
||||
$y = 2100;
|
||||
|
||||
$nextyear = $y;
|
||||
$nextmonth = $m + 1;
|
||||
if($nextmonth > 12) {
|
||||
$nextmonth = 1;
|
||||
$nextyear ++;
|
||||
}
|
||||
|
||||
$prevyear = $y;
|
||||
if($m > 1)
|
||||
$prevmonth = $m - 1;
|
||||
else {
|
||||
$prevmonth = 12;
|
||||
$prevyear --;
|
||||
}
|
||||
|
||||
$dim = get_dim($y,$m);
|
||||
$start = sprintf('%d-%d-%d %d:%d:%d',$y,$m,1,0,0,0);
|
||||
$finish = sprintf('%d-%d-%d %d:%d:%d',$y,$m,$dim,23,59,59);
|
||||
|
||||
|
||||
if (argv(2) === 'json'){
|
||||
if (x($_GET,'start')) $start = $_GET['start'];
|
||||
if (x($_GET,'end')) $finish = $_GET['end'];
|
||||
}
|
||||
|
||||
$start = datetime_convert('UTC','UTC',$start);
|
||||
$finish = datetime_convert('UTC','UTC',$finish);
|
||||
|
||||
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
|
||||
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
|
||||
|
||||
$start = datetime_convert('UTC','UTC',$start);
|
||||
$finish = datetime_convert('UTC','UTC',$finish);
|
||||
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
|
||||
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
|
||||
|
||||
if(! perm_is_allowed(\App::$profile['uid'],get_observer_hash(),'view_contacts'))
|
||||
$sql_extra .= " and etype != 'birthday' ";
|
||||
if (x($_GET, 'id')) {
|
||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
|
||||
from event left join item on item.resource_id = event.event_hash
|
||||
where item.resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
|
||||
intval($channel['channel_id']),
|
||||
intval($_GET['id'])
|
||||
);
|
||||
}
|
||||
else {
|
||||
// fixed an issue with "nofinish" events not showing up in the calendar.
|
||||
// There's still an issue if the finish date crosses the end of month.
|
||||
// Noting this for now - it will need to be fixed here and in Friendica.
|
||||
// Ultimately the finish date shouldn't be involved in the query.
|
||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
|
||||
from event left join item on event.event_hash = item.resource_id
|
||||
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid
|
||||
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
|
||||
OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' ))
|
||||
$sql_extra",
|
||||
intval($channel['channel_id']),
|
||||
dbesc($start),
|
||||
dbesc($finish),
|
||||
dbesc($adjust_start),
|
||||
dbesc($adjust_finish)
|
||||
);
|
||||
}
|
||||
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$r = fetch_post_tags($r,true);
|
||||
$r = sort_by_date($r);
|
||||
}
|
||||
|
||||
if (x($_GET,'id')){
|
||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
|
||||
from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
|
||||
intval($channel['channel_id']),
|
||||
intval($_GET['id'])
|
||||
);
|
||||
}
|
||||
else {
|
||||
// fixed an issue with "nofinish" events not showing up in the calendar.
|
||||
// There's still an issue if the finish date crosses the end of month.
|
||||
// Noting this for now - it will need to be fixed here and in Friendica.
|
||||
// Ultimately the finish date shouldn't be involved in the query.
|
||||
$events = [];
|
||||
|
||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
|
||||
from event left join item on event_hash = resource_id
|
||||
where resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored
|
||||
AND (( adjust = 0 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )
|
||||
OR ( adjust = 1 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )) $sql_extra ",
|
||||
intval($channel['channel_id']),
|
||||
dbesc($start),
|
||||
dbesc($finish),
|
||||
dbesc($adjust_start),
|
||||
dbesc($adjust_finish)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$links = array();
|
||||
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$r = fetch_post_tags($r,true);
|
||||
|
||||
$r = sort_by_date($r);
|
||||
}
|
||||
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
|
||||
if(! x($links,$j))
|
||||
$links[$j] = z_root() . '/' . \App::$cmd . '#link-' . $j;
|
||||
if($r) {
|
||||
|
||||
foreach($r as $rr) {
|
||||
|
||||
$tz = get_iconfig($rr, 'event', 'timezone');
|
||||
if(! $tz)
|
||||
$tz = 'UTC';
|
||||
|
||||
$start = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
|
||||
if ($rr['nofinish']){
|
||||
$end = null;
|
||||
} else {
|
||||
$end = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
|
||||
}
|
||||
}
|
||||
|
||||
$events=array();
|
||||
|
||||
$last_date = '';
|
||||
$fmt = t('l, F j');
|
||||
|
||||
if($r) {
|
||||
|
||||
foreach($r as $rr) {
|
||||
|
||||
$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
|
||||
$d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt));
|
||||
$d = day_translate($d);
|
||||
|
||||
$start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c'));
|
||||
if ($rr['nofinish']){
|
||||
$end = null;
|
||||
} else {
|
||||
$end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c'));
|
||||
}
|
||||
|
||||
|
||||
$is_first = ($d !== $last_date);
|
||||
|
||||
$last_date = $d;
|
||||
|
||||
$edit = false;
|
||||
|
||||
$drop = false;
|
||||
|
||||
$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
|
||||
if(! $title) {
|
||||
list($title, $_trash) = explode("<br",bbcode($rr['desc']),2);
|
||||
$title = strip_tags(html_entity_decode($title,ENT_QUOTES,'UTF-8'));
|
||||
}
|
||||
|
||||
$html = '';
|
||||
if (x($_GET,'id')) {
|
||||
$rr['timezone'] = $tz;
|
||||
$html = format_event_html($rr);
|
||||
$rr['desc'] = zidify_links(smilies(bbcode($rr['desc'])));
|
||||
$rr['description'] = htmlentities(html2plain(bbcode($rr['description'])),ENT_COMPAT,'UTF-8',false);
|
||||
$rr['location'] = zidify_links(smilies(bbcode($rr['location'])));
|
||||
$events[] = array(
|
||||
'id'=>$rr['id'],
|
||||
'hash' => $rr['event_hash'],
|
||||
'start'=> $start,
|
||||
'end' => $end,
|
||||
'drop' => $drop,
|
||||
'allDay' => false,
|
||||
'title' => $title,
|
||||
|
||||
'j' => $j,
|
||||
'd' => $d,
|
||||
'edit' => $edit,
|
||||
'is_first'=>$is_first,
|
||||
'item'=>$rr,
|
||||
'html'=>$html,
|
||||
'plink' => array($rr['plink'],t('Link to Source'),'',''),
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
$events[] = array(
|
||||
'calendar_id' => 'channel_calendar',
|
||||
'rw' => true,
|
||||
'id'=>$rr['id'],
|
||||
'uri' => $rr['event_hash'],
|
||||
'timezone' => $tz,
|
||||
'start'=> $start,
|
||||
'end' => $end,
|
||||
'drop' => $drop,
|
||||
'allDay' => (($rr['adjust']) ? 0 : 1),
|
||||
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
|
||||
'editable' => $edit ? true : false,
|
||||
'item' => $rr,
|
||||
'plink' => [$rr['plink'], t('Link to source')],
|
||||
'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'),
|
||||
'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'),
|
||||
'allow_cid' => expand_acl($rr['allow_cid']),
|
||||
'allow_gid' => expand_acl($rr['allow_gid']),
|
||||
'deny_cid' => expand_acl($rr['deny_cid']),
|
||||
'deny_gid' => expand_acl($rr['deny_gid']),
|
||||
'html' => $html
|
||||
);
|
||||
}
|
||||
|
||||
if (argv(2) === 'json'){
|
||||
echo json_encode($events); killme();
|
||||
}
|
||||
|
||||
// links: array('href', 'text', 'extra css classes', 'title')
|
||||
if (x($_GET,'id')){
|
||||
$tpl = get_markup_template("event_cal.tpl");
|
||||
}
|
||||
else {
|
||||
$tpl = get_markup_template("events_cal-js.tpl");
|
||||
}
|
||||
|
||||
$nick = $channel['channel_address'];
|
||||
|
||||
$o = replace_macros($tpl, array(
|
||||
'$baseurl' => z_root(),
|
||||
'$new_event' => array(z_root().'/cal',(($event_id) ? t('Edit Event') : t('Create Event')),'',''),
|
||||
'$previus' => array(z_root()."/cal/$nick/$prevyear/$prevmonth",t('Previous'),'',''),
|
||||
'$next' => array(z_root()."/cal/$nick/$nextyear/$nextmonth",t('Next'),'',''),
|
||||
'$export' => array(z_root()."/cal/$nick/$y/$m/export",t('Export'),'',''),
|
||||
'$calendar' => cal($y,$m,$links, ' eventcal'),
|
||||
'$events' => $events,
|
||||
'$upload' => t('Import'),
|
||||
'$submit' => t('Submit'),
|
||||
'$prev' => t('Previous'),
|
||||
'$next' => t('Next'),
|
||||
'$today' => t('Today'),
|
||||
'$form' => $form,
|
||||
'$expandform' => ((x($_GET,'expandform')) ? true : false)
|
||||
));
|
||||
|
||||
if (x($_GET,'id')){ echo $o; killme(); }
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
if (argv(2) === 'json') {
|
||||
echo json_encode($events);
|
||||
killme();
|
||||
}
|
||||
|
||||
if (x($_GET,'id')) {
|
||||
$o = replace_macros(get_markup_template("cal_event.tpl"), [
|
||||
'$events' => $events
|
||||
]);
|
||||
echo $o;
|
||||
killme();
|
||||
}
|
||||
|
||||
$nick = $channel['channel_address'];
|
||||
|
||||
$sources = '{
|
||||
id: \'channel_calendar\',
|
||||
url: \'/cal/' . $nick . '/json/\',
|
||||
color: \'#3a87ad\'
|
||||
}';
|
||||
|
||||
$o = replace_macros(get_markup_template("cal_calendar.tpl"), [
|
||||
'$sources' => $sources,
|
||||
'$lang' => App::$language,
|
||||
'$timezone' => date_default_timezone_get(),
|
||||
'$first_day' => $first_day,
|
||||
'$prev' => t('Previous'),
|
||||
'$next' => t('Next'),
|
||||
'$today' => t('Today'),
|
||||
'$title' => $title,
|
||||
'$dtstart' => $dtstart,
|
||||
'$dtend' => $dtend,
|
||||
'$nick' => $nick
|
||||
]);
|
||||
|
||||
return $o;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ class Cards extends Controller {
|
||||
|
||||
|
||||
$itemspage = get_pconfig(local_channel(),'system','itemspage');
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
|
||||
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ class Changeaddr extends \Zotlabs\Web\Controller {
|
||||
|
||||
if($account['account_password_changed'] > NULL_DATE) {
|
||||
$d1 = datetime_convert('UTC','UTC','now - 48 hours');
|
||||
if($account['account_password_changed'] > d1) {
|
||||
if($account['account_password_changed'] > $d1) {
|
||||
notice( t('Channel name changes are not allowed within 48 hours of changing the account password.') . EOL);
|
||||
return;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class Changeaddr extends \Zotlabs\Web\Controller {
|
||||
|
||||
if(check_webbie(array($new_address)) !== $new_address) {
|
||||
notice( t('Nickname has unsupported characters or is already being used on this site.') . EOL);
|
||||
return $ret;
|
||||
return;
|
||||
}
|
||||
|
||||
channel_change_address($channel,$new_address);
|
||||
|
||||
@@ -6,13 +6,14 @@ namespace Zotlabs\Module;
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\PermissionDescription;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/items.php');
|
||||
require_once('include/security.php');
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/acl_selectors.php');
|
||||
require_once('include/opengraph.php');
|
||||
|
||||
|
||||
/**
|
||||
@@ -46,20 +47,20 @@ class Channel extends Controller {
|
||||
$channel = App::get_channel();
|
||||
|
||||
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
}
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
}
|
||||
|
||||
$channel = channelx_by_nick($which);
|
||||
if(! $channel) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
if(! $channel) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
// handle zot6 channel discovery
|
||||
|
||||
if(Libzot::is_zot_request()) {
|
||||
|
||||
$sigdata = HTTPSig::verify(file_get_contents('php://input'));
|
||||
$sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6');
|
||||
|
||||
if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) {
|
||||
$data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'], 'target_url' => $sigdata['signer'] ]));
|
||||
@@ -109,17 +110,26 @@ class Channel extends Controller {
|
||||
|
||||
// Run profile_load() here to make sure the theme is set before
|
||||
// we start loading content
|
||||
|
||||
profile_load($which,$profile);
|
||||
|
||||
// Add Opengraph markup
|
||||
$mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
|
||||
if(strpos($mid,'b64.') === 0)
|
||||
$mid = @base64url_decode(substr($mid,4));
|
||||
|
||||
if($mid)
|
||||
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
|
||||
dbesc($mid),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
opengraph_add_meta($r ? $r[0] : [], $channel);
|
||||
}
|
||||
|
||||
function get($update = 0, $load = false) {
|
||||
|
||||
$noscript_content = get_config('system', 'noscript_content', '1');
|
||||
|
||||
if($load)
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
|
||||
$category = $datequery = $datequery2 = '';
|
||||
|
||||
$mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
|
||||
@@ -139,7 +149,6 @@ class Channel extends Controller {
|
||||
$category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : '');
|
||||
$hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : '');
|
||||
$order = ((x($_GET,'order')) ? notags($_GET['order']) : 'post');
|
||||
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
|
||||
$search = ((x($_GET,'search')) ? $_GET['search'] : EMPTY_STR);
|
||||
|
||||
$groups = array();
|
||||
@@ -174,8 +183,6 @@ class Channel extends Controller {
|
||||
|
||||
nav_set_selected('Channel Home');
|
||||
|
||||
$static = channel_manual_conv_update(App::$profile['profile_uid']);
|
||||
|
||||
// search terms header
|
||||
if($search) {
|
||||
$o .= replace_macros(get_markup_template("section_title.tpl"),array(
|
||||
@@ -226,8 +233,12 @@ class Channel extends Controller {
|
||||
/**
|
||||
* Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups
|
||||
*/
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0
|
||||
and item.item_unpublished = 0 and item.item_pending_remove = 0
|
||||
and item.item_blocked = 0 ";
|
||||
if (! $is_owner)
|
||||
$item_normal .= "and item.item_delayed = 0 ";
|
||||
$item_normal_update = item_normal_update();
|
||||
$sql_extra = item_permissions_sql(App::$profile['profile_uid']);
|
||||
|
||||
@@ -238,7 +249,9 @@ class Channel extends Controller {
|
||||
|
||||
$abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " ";
|
||||
|
||||
$simple_update = (($update) ? " AND item_unseen = 1 " : '');
|
||||
$simple_update = '';
|
||||
if($update && $_SESSION['loadtime'])
|
||||
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
|
||||
|
||||
if($search) {
|
||||
$search = escape_tags($search);
|
||||
@@ -253,7 +266,6 @@ class Channel extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
head_add_link([
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/json+oembed',
|
||||
@@ -261,14 +273,6 @@ class Channel extends Controller {
|
||||
'title' => 'oembed'
|
||||
]);
|
||||
|
||||
if($update && $_SESSION['loadtime'])
|
||||
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
|
||||
if($load)
|
||||
$simple_update = '';
|
||||
|
||||
if($static && $simple_update)
|
||||
$simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
|
||||
|
||||
if(($update) && (! $load)) {
|
||||
|
||||
if($mid) {
|
||||
@@ -277,7 +281,6 @@ class Channel extends Controller {
|
||||
dbesc($mid . '%'),
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
}
|
||||
else {
|
||||
$r = q("SELECT parent AS item_id from item
|
||||
@@ -289,9 +292,7 @@ class Channel extends Controller {
|
||||
ORDER BY created DESC",
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -310,10 +311,6 @@ class Channel extends Controller {
|
||||
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2))));
|
||||
}
|
||||
|
||||
if($datequery || $datequery2) {
|
||||
$sql_extra2 .= " and item.item_thread_top != 0 ";
|
||||
}
|
||||
|
||||
if($order === 'post')
|
||||
$ordering = "created";
|
||||
else
|
||||
@@ -321,7 +318,7 @@ class Channel extends Controller {
|
||||
|
||||
|
||||
$itemspage = get_pconfig(local_channel(),'system','itemspage');
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
|
||||
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
|
||||
|
||||
if($noscript_content || $load) {
|
||||
@@ -342,7 +339,7 @@ class Channel extends Controller {
|
||||
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
|
||||
AND item.item_wall = 1 AND item.item_thread_top = 1
|
||||
$sql_extra $sql_extra2
|
||||
ORDER BY $ordering DESC $pager_sql ",
|
||||
ORDER BY $ordering DESC, item_id $pager_sql ",
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
}
|
||||
@@ -355,7 +352,7 @@ class Channel extends Controller {
|
||||
|
||||
$parents_str = ids_to_querystr($r,'item_id');
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id
|
||||
$r = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE item.uid = %d $item_normal
|
||||
AND item.parent IN ( %s )
|
||||
@@ -364,8 +361,8 @@ class Channel extends Controller {
|
||||
dbesc($parents_str)
|
||||
);
|
||||
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
$items = conv_sort($items,$ordering);
|
||||
|
||||
if($load && $mid && (! count($items))) {
|
||||
@@ -393,7 +390,7 @@ class Channel extends Controller {
|
||||
$o .= '<div id="live-channel"></div>' . "\r\n";
|
||||
$o .= "<script> var profile_uid = " . App::$profile['profile_uid']
|
||||
. "; var netargs = '?f='; var profile_page = " . App::$pager['page']
|
||||
. "; divmore_height = " . intval($maxheight) . "; </script>\r\n";
|
||||
. "; divmore_height = " . intval($maxheight) . ";</script>\r\n";
|
||||
|
||||
App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
|
||||
'$baseurl' => z_root(),
|
||||
@@ -410,54 +407,30 @@ class Channel extends Controller {
|
||||
'$nouveau' => '0',
|
||||
'$wall' => '1',
|
||||
'$fh' => '0',
|
||||
'$static' => $static,
|
||||
'$dm' => '0',
|
||||
'$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1),
|
||||
'$search' => $search,
|
||||
'$xchan' => '',
|
||||
'$order' => $order,
|
||||
'$order' => (($order) ? urlencode($order) : ''),
|
||||
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
|
||||
'$file' => '',
|
||||
'$cats' => (($category) ? urlencode($category) : ''),
|
||||
'$tags' => (($hashtags) ? urlencode($hashtags) : ''),
|
||||
'$mid' => $mid,
|
||||
'$mid' => (($mid) ? urlencode($mid) : ''),
|
||||
'$verb' => '',
|
||||
'$net' => '',
|
||||
'$dend' => $datequery,
|
||||
'$dbegin' => $datequery2
|
||||
'$dbegin' => $datequery2,
|
||||
'$conv_mode' => 'channel'
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
$update_unseen = '';
|
||||
|
||||
if($page_mode === 'list') {
|
||||
|
||||
/**
|
||||
* in "list mode", only mark the parent item and any like activities as "seen".
|
||||
* We won't distinguish between comment likes and post likes. The important thing
|
||||
* is that the number of unseen comments will be accurate. The SQL to separate the
|
||||
* comment likes could also get somewhat hairy.
|
||||
*/
|
||||
|
||||
if($parents_str) {
|
||||
$update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
|
||||
$update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($parents_str) {
|
||||
$update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
|
||||
}
|
||||
}
|
||||
|
||||
if($is_owner && $update_unseen) {
|
||||
$x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
|
||||
call_hooks('update_unseen',$x);
|
||||
if($x['update'] === 'unset' || intval($x['update'])) {
|
||||
$r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen",
|
||||
intval(local_channel())
|
||||
);
|
||||
}
|
||||
// Add pinned content
|
||||
if(! x($_REQUEST,'mid') && ! $search) {
|
||||
$pinned = new \Zotlabs\Widget\Pinned;
|
||||
$r = $pinned->widget(intval(App::$profile['profile_uid']), [ITEM_TYPE_POST]);
|
||||
$o .= $r['html'];
|
||||
}
|
||||
|
||||
$mode = (($search) ? 'search' : 'channel');
|
||||
@@ -487,6 +460,8 @@ class Channel extends Controller {
|
||||
if($mid)
|
||||
$o .= '<div id="content-complete"></div>';
|
||||
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
|
||||
501
Zotlabs/Module/Channel_calendar.php
Normal file
501
Zotlabs/Module/Channel_calendar.php
Normal file
@@ -0,0 +1,501 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/datetime.php');
|
||||
require_once('include/event.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
class Channel_calendar extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
|
||||
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
$event_id = ((x($_POST,'event_id')) ? intval($_POST['event_id']) : 0);
|
||||
$event_hash = ((x($_POST,'event_hash')) ? $_POST['event_hash'] : '');
|
||||
|
||||
$xchan = ((x($_POST,'xchan')) ? dbesc($_POST['xchan']) : '');
|
||||
$uid = local_channel();
|
||||
|
||||
// only allow editing your own events.
|
||||
if(($xchan) && ($xchan !== get_observer_hash()))
|
||||
return;
|
||||
|
||||
$categories = escape_tags(trim($_POST['categories']));
|
||||
|
||||
// allday events have adjust = 0, normal events have adjust = 1
|
||||
$adjust = intval($_POST['adjust']);
|
||||
|
||||
$start = datetime_convert((($adjust) ? $tz : 'UTC'), 'UTC', escape_tags($_REQUEST['dtstart']));
|
||||
$finish = datetime_convert((($adjust) ? $tz : 'UTC'), 'UTC', escape_tags($_REQUEST['dtend']));
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
if(! $adjust)
|
||||
$tz = 'UTC';
|
||||
|
||||
$summary = escape_tags(trim($_POST['summary']));
|
||||
$desc = escape_tags(trim($_POST['desc']));
|
||||
$location = escape_tags(trim($_POST['location']));
|
||||
$type = escape_tags(trim($_POST['type']));
|
||||
|
||||
// Don't allow the event to finish before it begins.
|
||||
// It won't hurt anything, but somebody will file a bug report
|
||||
// and we'll waste a bunch of time responding to it. Time that
|
||||
// could've been spent doing something else.
|
||||
|
||||
if(strcmp($finish,$start) < 0 && !$nofinish) {
|
||||
notice( t('Event can not end before it has started.') . EOL);
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
echo( t('Unable to generate preview.'));
|
||||
}
|
||||
killme();
|
||||
}
|
||||
|
||||
if((! $summary) || (! $start)) {
|
||||
notice( t('Event title and start time are required.') . EOL);
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
echo( t('Unable to generate preview.'));
|
||||
}
|
||||
killme();
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
$acl = new \Zotlabs\Access\AccessList(false);
|
||||
|
||||
if($event_id) {
|
||||
$x = q("select * from event where id = %d and uid = %d limit 1",
|
||||
intval($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
if(! $x) {
|
||||
notice( t('Event not found.') . EOL);
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
echo( t('Unable to generate preview.'));
|
||||
killme();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$acl->set($x[0]);
|
||||
|
||||
$created = $x[0]['created'];
|
||||
$edited = datetime_convert();
|
||||
}
|
||||
else {
|
||||
$created = $edited = datetime_convert();
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
|
||||
$post_tags = array();
|
||||
$channel = \App::get_channel();
|
||||
$ac = $acl->get();
|
||||
|
||||
$str_contact_allow = $ac['allow_cid'];
|
||||
$str_group_allow = $ac['allow_gid'];
|
||||
$str_contact_deny = $ac['deny_cid'];
|
||||
$str_group_deny = $ac['deny_gid'];
|
||||
|
||||
$private = $acl->is_private();
|
||||
|
||||
require_once('include/text.php');
|
||||
$results = linkify_tags($desc, local_channel());
|
||||
|
||||
if($results) {
|
||||
// Set permissions based on tag replacements
|
||||
set_linkified_perms($results, $str_contact_allow, $str_group_allow, local_channel(), false, $private);
|
||||
|
||||
foreach($results as $result) {
|
||||
$success = $result['success'];
|
||||
if($success['replaced']) {
|
||||
$post_tags[] = array(
|
||||
'uid' => local_channel(),
|
||||
'ttype' => $success['termtype'],
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'term' => $success['term'],
|
||||
'url' => $success['url']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(strlen($categories)) {
|
||||
$cats = explode(',',$categories);
|
||||
foreach($cats as $cat) {
|
||||
$post_tags[] = array(
|
||||
'uid' => local_channel(),
|
||||
'ttype' => TERM_CATEGORY,
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'term' => trim($cat),
|
||||
'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$datarray = array();
|
||||
$datarray['dtstart'] = $start;
|
||||
$datarray['dtend'] = $finish;
|
||||
$datarray['summary'] = $summary;
|
||||
$datarray['description'] = $desc;
|
||||
$datarray['location'] = $location;
|
||||
$datarray['etype'] = $type;
|
||||
$datarray['adjust'] = $adjust;
|
||||
$datarray['nofinish'] = 0;
|
||||
$datarray['uid'] = local_channel();
|
||||
$datarray['account'] = get_account_id();
|
||||
$datarray['event_xchan'] = $channel['channel_hash'];
|
||||
$datarray['allow_cid'] = $str_contact_allow;
|
||||
$datarray['allow_gid'] = $str_group_allow;
|
||||
$datarray['deny_cid'] = $str_contact_deny;
|
||||
$datarray['deny_gid'] = $str_group_deny;
|
||||
$datarray['private'] = intval($private);
|
||||
$datarray['id'] = $event_id;
|
||||
$datarray['created'] = $created;
|
||||
$datarray['edited'] = $edited;
|
||||
$datarray['timezone'] = $tz;
|
||||
|
||||
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
$html = format_event_html($datarray);
|
||||
echo $html;
|
||||
killme();
|
||||
}
|
||||
|
||||
$event = event_store_event($datarray);
|
||||
|
||||
if($post_tags)
|
||||
$datarray['term'] = $post_tags;
|
||||
|
||||
$item_id = event_store_item($datarray,$event);
|
||||
|
||||
if($item_id) {
|
||||
$r = q("select * from item where id = %d",
|
||||
intval($item_id)
|
||||
);
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$sync_item = fetch_post_tags($r);
|
||||
$z = q("select * from event where event_hash = '%s' and uid = %d limit 1",
|
||||
dbesc($r[0]['resource_id']),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if($z) {
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('event_item' => array(encode_item($sync_item[0],true)),'event' => $z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\Zotlabs\Daemon\Master::Summon(array('Notifier','event',$item_id));
|
||||
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
if(argc() > 2 && argv(1) == 'ical') {
|
||||
$event_id = argv(2);
|
||||
|
||||
require_once('include/security.php');
|
||||
$sql_extra = permissions_sql(local_channel());
|
||||
|
||||
$r = q("select * from event where event_hash = '%s' $sql_extra limit 1",
|
||||
dbesc($event_id)
|
||||
);
|
||||
if($r) {
|
||||
header('Content-type: text/calendar');
|
||||
header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"' );
|
||||
echo ical_wrapper($r);
|
||||
killme();
|
||||
}
|
||||
else {
|
||||
notice( t('Event not found.') . EOL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(! local_channel()) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
|
||||
$r = q("update event set dismissed = 1 where id = %d and uid = %d",
|
||||
intval(argv(2)),
|
||||
intval(local_channel())
|
||||
);
|
||||
}
|
||||
|
||||
if((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) {
|
||||
$r = q("update event set dismissed = 0 where id = %d and uid = %d",
|
||||
intval(argv(2)),
|
||||
intval(local_channel())
|
||||
);
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
$mode = 'view';
|
||||
$export = false;
|
||||
$ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
|
||||
|
||||
if(argc() > 1) {
|
||||
if(argc() > 2 && argv(1) === 'add') {
|
||||
$mode = 'add';
|
||||
$item_id = intval(argv(2));
|
||||
}
|
||||
if(argc() > 2 && argv(1) === 'drop') {
|
||||
$mode = 'drop';
|
||||
$event_id = argv(2);
|
||||
}
|
||||
if(argc() <= 2 && argv(1) === 'export') {
|
||||
$export = true;
|
||||
}
|
||||
if(argc() > 2 && intval(argv(1)) && intval(argv(2))) {
|
||||
$mode = 'view';
|
||||
}
|
||||
if(argc() <= 2) {
|
||||
$mode = 'view';
|
||||
$event_id = argv(1);
|
||||
}
|
||||
}
|
||||
|
||||
if($mode === 'add') {
|
||||
event_addtocal($item_id,local_channel());
|
||||
killme();
|
||||
}
|
||||
|
||||
if($mode == 'view') {
|
||||
|
||||
/* edit/create form */
|
||||
if($event_id) {
|
||||
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
if(count($r))
|
||||
$orig_event = $r[0];
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
if (argv(1) === 'json'){
|
||||
if (x($_GET,'start')) $start = $_GET['start'];
|
||||
if (x($_GET,'end')) $finish = $_GET['end'];
|
||||
}
|
||||
|
||||
$start = datetime_convert('UTC','UTC',$start);
|
||||
$finish = datetime_convert('UTC','UTC',$finish);
|
||||
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
|
||||
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
|
||||
|
||||
if (x($_GET,'id')){
|
||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
|
||||
from event left join item on item.resource_id = event.event_hash
|
||||
where item.resource_type = 'event' and event.uid = %d and event.id = %d limit 1",
|
||||
intval(local_channel()),
|
||||
intval($_GET['id'])
|
||||
);
|
||||
}
|
||||
elseif($export) {
|
||||
$r = q("SELECT event.*, item.id as item_id
|
||||
from event left join item on item.resource_id = event.event_hash
|
||||
where event.uid = %d and event.dtstart > '%s' and event.dtend > event.dtstart",
|
||||
intval(local_channel()),
|
||||
dbesc(NULL_DATE)
|
||||
);
|
||||
}
|
||||
else {
|
||||
// fixed an issue with "nofinish" events not showing up in the calendar.
|
||||
// There's still an issue if the finish date crosses the end of month.
|
||||
// Noting this for now - it will need to be fixed here and in Friendica.
|
||||
// Ultimately the finish date shouldn't be involved in the query.
|
||||
|
||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
|
||||
from event left join item on event.event_hash = item.resource_id
|
||||
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored
|
||||
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
|
||||
OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )) ",
|
||||
intval(local_channel()),
|
||||
dbesc($start),
|
||||
dbesc($finish),
|
||||
dbesc($adjust_start),
|
||||
dbesc($adjust_finish)
|
||||
);
|
||||
}
|
||||
|
||||
if($r && ! $export) {
|
||||
xchan_query($r);
|
||||
$r = fetch_post_tags($r,true);
|
||||
$r = sort_by_date($r);
|
||||
}
|
||||
|
||||
$events = [];
|
||||
|
||||
if($r) {
|
||||
|
||||
foreach($r as $rr) {
|
||||
|
||||
$start = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
|
||||
if ($rr['nofinish']){
|
||||
$end = null;
|
||||
} else {
|
||||
$end = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
|
||||
}
|
||||
|
||||
$catsenabled = feature_enabled(local_channel(),'categories');
|
||||
$categories = '';
|
||||
if($catsenabled){
|
||||
if($rr['term']) {
|
||||
$cats = get_terms_oftype($rr['term'], TERM_CATEGORY);
|
||||
foreach ($cats as $cat) {
|
||||
if(strlen($categories))
|
||||
$categories .= ', ';
|
||||
$categories .= $cat['term'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root().'/events/'.$rr['event_hash'].'?expandform=1',t('Edit event'),'','') : false);
|
||||
|
||||
$drop = array(z_root().'/events/drop/'.$rr['event_hash'],t('Delete event'),'','');
|
||||
|
||||
$tz = get_iconfig($rr, 'event', 'timezone');
|
||||
|
||||
if(! $tz)
|
||||
$tz = 'UTC';
|
||||
|
||||
$events[] = array(
|
||||
'calendar_id' => 'channel_calendar',
|
||||
'rw' => true,
|
||||
'id'=>$rr['id'],
|
||||
'uri' => $rr['event_hash'],
|
||||
'timezone' => $tz,
|
||||
'start'=> $start,
|
||||
'end' => $end,
|
||||
'drop' => $drop,
|
||||
'allDay' => (($rr['adjust']) ? 0 : 1),
|
||||
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
|
||||
'editable' => $edit ? true : false,
|
||||
'item' => $rr,
|
||||
'plink' => [$rr['plink'], t('Link to source')],
|
||||
'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'),
|
||||
'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'),
|
||||
'allow_cid' => expand_acl($rr['allow_cid']),
|
||||
'allow_gid' => expand_acl($rr['allow_gid']),
|
||||
'deny_cid' => expand_acl($rr['deny_cid']),
|
||||
'deny_gid' => expand_acl($rr['deny_gid']),
|
||||
'categories' => $categories
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if($export) {
|
||||
header('Content-type: text/calendar');
|
||||
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );
|
||||
echo ical_wrapper($r);
|
||||
killme();
|
||||
}
|
||||
|
||||
if (\App::$argv[1] === 'json'){
|
||||
json_return_and_die($events);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($mode === 'drop' && $event_id) {
|
||||
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
$sync_event = $r[0];
|
||||
|
||||
if($r) {
|
||||
$r = q("delete from event where event_hash = '%s' and uid = %d",
|
||||
dbesc($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if($r) {
|
||||
|
||||
$sync_event['event_deleted'] = 1;
|
||||
Libsync::build_sync_packet(0,array('event' => array($sync_event)));
|
||||
|
||||
$i = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d",
|
||||
dbesc($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if ($i) {
|
||||
|
||||
$can_delete = false;
|
||||
$local_delete = true;
|
||||
|
||||
$ob_hash = get_observer_hash();
|
||||
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) {
|
||||
$can_delete = true;
|
||||
}
|
||||
|
||||
// The site admin can delete any post/item on the site.
|
||||
// If the item originated on this site+channel the deletion will propagate downstream.
|
||||
// Otherwise just the local copy is removed.
|
||||
|
||||
if(is_site_admin()) {
|
||||
$local_delete = true;
|
||||
if(intval($i[0]['item_origin']))
|
||||
$can_delete = true;
|
||||
}
|
||||
|
||||
if($can_delete || $local_delete) {
|
||||
|
||||
// if this is a different page type or it's just a local delete
|
||||
// but not by the item author or owner, do a simple deletion
|
||||
|
||||
$complex = false;
|
||||
|
||||
if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) {
|
||||
drop_item($i[0]['id']);
|
||||
}
|
||||
else {
|
||||
// complex deletion that needs to propagate and be performed in phases
|
||||
drop_item($i[0]['id'],true,DROPITEM_PHASE1);
|
||||
$complex = true;
|
||||
}
|
||||
|
||||
$ii = q("select * from item where id = %d",
|
||||
intval($i[0]['id'])
|
||||
);
|
||||
if($ii) {
|
||||
xchan_query($ii);
|
||||
$sync_item = fetch_post_tags($ii);
|
||||
Libsync::build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
|
||||
}
|
||||
|
||||
if($complex) {
|
||||
tag_deliver($i[0]['uid'],$i[0]['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
killme();
|
||||
}
|
||||
notice( t('Failed to remove event' ) . EOL);
|
||||
killme();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +1,35 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/zot.php');
|
||||
use App;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Webfinger;
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
|
||||
|
||||
class Chanview extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
$observer = \App::get_observer();
|
||||
$observer = App::get_observer();
|
||||
$xchan = null;
|
||||
|
||||
$r = null;
|
||||
|
||||
if($_REQUEST['hash']) {
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
$r = q("select * from xchan where xchan_hash = '%s'",
|
||||
dbesc($_REQUEST['hash'])
|
||||
);
|
||||
}
|
||||
if($_REQUEST['address']) {
|
||||
$r = q("select * from xchan where xchan_addr = '%s' limit 1",
|
||||
$r = q("select * from xchan where xchan_addr = '%s'",
|
||||
dbesc(punify($_REQUEST['address']))
|
||||
);
|
||||
}
|
||||
elseif(local_channel() && intval($_REQUEST['cid'])) {
|
||||
$r = q("SELECT abook.*, xchan.*
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d and abook_id = %d LIMIT 1",
|
||||
WHERE abook_channel = %d and abook_id = %d",
|
||||
intval(local_channel()),
|
||||
intval($_REQUEST['cid'])
|
||||
);
|
||||
@@ -35,12 +39,12 @@ class Chanview extends \Zotlabs\Web\Controller {
|
||||
// if somebody re-installed they will have more than one xchan, use the most recent name date as this is
|
||||
// the most useful consistently ascending table item we have.
|
||||
|
||||
$r = q("select * from xchan where xchan_url = '%s' order by xchan_name_date desc limit 1",
|
||||
$r = q("select * from xchan where xchan_url = '%s' order by xchan_name_date desc",
|
||||
dbesc($_REQUEST['url'])
|
||||
);
|
||||
}
|
||||
if($r) {
|
||||
\App::$poi = $r[0];
|
||||
App::$poi = Libzot::zot_record_preferred($r, 'xchan_network');
|
||||
}
|
||||
|
||||
|
||||
@@ -49,74 +53,63 @@ class Chanview extends \Zotlabs\Web\Controller {
|
||||
// address, we can and should try to import it. If it's just a hash, we can't continue, but we
|
||||
// probably wouldn't have a hash if we don't already have an xchan for this channel.
|
||||
|
||||
if(! \App::$poi) {
|
||||
if(! App::$poi) {
|
||||
logger('mod_chanview: fallback');
|
||||
// This is hackish - construct a zot address from the url
|
||||
if($_REQUEST['url']) {
|
||||
if(preg_match('/https?\:\/\/(.*?)(\/channel\/|\/profile\/)(.*?)$/ism',$_REQUEST['url'],$matches)) {
|
||||
$_REQUEST['address'] = $matches[3] . '@' . $matches[1];
|
||||
|
||||
if($_REQUEST['address']) {
|
||||
$href = Webfinger::zot_url(punify($_REQUEST['address']));
|
||||
if($href) {
|
||||
$_REQUEST['url'] = $href;
|
||||
}
|
||||
logger('mod_chanview: constructed address ' . print_r($matches,true));
|
||||
}
|
||||
|
||||
$r = null;
|
||||
|
||||
if($_REQUEST['address']) {
|
||||
$j = \Zotlabs\Zot\Finger::run($_REQUEST['address'],null);
|
||||
if($j['success']) {
|
||||
import_xchan($j);
|
||||
$r = q("select * from xchan where xchan_addr = '%s' limit 1",
|
||||
dbesc($_REQUEST['address'])
|
||||
if($_REQUEST['url']) {
|
||||
|
||||
$zf = Zotfinger::exec($_REQUEST['url'], null);
|
||||
|
||||
if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $_REQUEST['url'] && intval($zf['signature']['header_valid'])) {
|
||||
Libzot::import_xchan($j);
|
||||
$r = q("select * from xchan where xchan_url = '%s'",
|
||||
dbesc($_REQUEST['url'])
|
||||
);
|
||||
if($r) {
|
||||
\App::$poi = $r[0];
|
||||
App::$poi = Libzot::zot_record_preferred($r, 'xchan_network');
|
||||
}
|
||||
}
|
||||
if(! $r) {
|
||||
if(discover_by_webbie($_REQUEST['address'])) {
|
||||
$r = q("select * from xchan where xchan_addr = '%s' limit 1",
|
||||
dbesc($_REQUEST['address'])
|
||||
if(discover_by_webbie($_REQUEST['url'])) {
|
||||
$r = q("select * from xchan where xchan_url = '%s'",
|
||||
dbesc($_REQUEST['url'])
|
||||
);
|
||||
if($r) {
|
||||
\App::$poi = $r[0];
|
||||
App::$poi = Libzot::zot_record_preferred($r, 'xchan_network');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(! \App::$poi) {
|
||||
|
||||
// We don't know who this is, and we can't figure it out from the URL
|
||||
// On the plus side, there's a good chance we know somebody else at that
|
||||
// hub so sending them there with a Zid will probably work anyway.
|
||||
|
||||
$url = ($_REQUEST['url']);
|
||||
if(! $url) {
|
||||
notice( t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
if($observer)
|
||||
$url = zid($url);
|
||||
|
||||
if(! App::$poi) {
|
||||
notice( t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$is_zot = false;
|
||||
$connected = false;
|
||||
|
||||
if (\App::$poi) {
|
||||
$url = \App::$poi['xchan_url'];
|
||||
if(in_array(\App::$poi['xchan_network'], ['zot', 'zot6'])) {
|
||||
$is_zot = true;
|
||||
}
|
||||
if(local_channel()) {
|
||||
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1",
|
||||
intval(local_channel()),
|
||||
dbesc(\App::$poi['xchan_hash'])
|
||||
);
|
||||
if($c)
|
||||
$connected = true;
|
||||
}
|
||||
$url = App::$poi['xchan_url'];
|
||||
if(in_array(App::$poi['xchan_network'], ['zot', 'zot6'])) {
|
||||
$is_zot = true;
|
||||
}
|
||||
if(local_channel()) {
|
||||
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1",
|
||||
intval(local_channel()),
|
||||
dbesc(App::$poi['xchan_hash'])
|
||||
);
|
||||
if($c)
|
||||
$connected = true;
|
||||
}
|
||||
|
||||
// We will load the chanview template if it's a foreign network,
|
||||
|
||||
@@ -7,9 +7,7 @@ use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Chatroom;
|
||||
use Zotlabs\Access\AccessList;
|
||||
|
||||
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
require_once('include/bookmarks.php');
|
||||
|
||||
@@ -80,7 +78,7 @@ class Chat extends Controller {
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
build_sync_packet(0, array('chatroom' => $x));
|
||||
Libsync::build_sync_packet(0, array('chatroom' => $x));
|
||||
|
||||
if($x)
|
||||
goaway(z_root() . '/chat/' . $channel['channel_address'] . '/' . $x[0]['cr_id']);
|
||||
@@ -199,7 +197,7 @@ class Chat extends Controller {
|
||||
|
||||
$cipher = get_pconfig(local_channel(),'system','default_cipher');
|
||||
if(! $cipher)
|
||||
$cipher = 'aes256';
|
||||
$cipher = 'AES-128-CCM';
|
||||
|
||||
|
||||
$o = replace_macros(get_markup_template('chat.tpl'),array(
|
||||
|
||||
@@ -35,13 +35,6 @@ class Cloud extends \Zotlabs\Web\Controller {
|
||||
if (argc() > 1)
|
||||
$which = argv(1);
|
||||
|
||||
|
||||
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
construct_page();
|
||||
killme();
|
||||
}
|
||||
|
||||
$profile = 0;
|
||||
|
||||
if ($which)
|
||||
|
||||
@@ -28,10 +28,6 @@ class Connect extends Controller {
|
||||
|
||||
$channel_id = App::$data['channel']['channel_id'];
|
||||
|
||||
if(! Apps::system_app_installed($channel_id, 'Premium Channel')) {
|
||||
return;
|
||||
}
|
||||
|
||||
profile_load($which,'');
|
||||
}
|
||||
|
||||
@@ -42,10 +38,6 @@ class Connect extends Controller {
|
||||
|
||||
$channel_id = App::$data['channel']['channel_id'];
|
||||
|
||||
if(! Apps::system_app_installed($channel_id, 'Premium Channel')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$edit = ((local_channel() && (local_channel() == $channel_id)) ? true : false);
|
||||
|
||||
if($edit) {
|
||||
@@ -97,15 +89,6 @@ class Connect extends Controller {
|
||||
|
||||
$channel_id = App::$data['channel']['channel_id'];
|
||||
|
||||
if(! Apps::system_app_installed($channel_id, 'Premium Channel')) {
|
||||
//Do not display any associated widgets at this point
|
||||
App::$pdl = '';
|
||||
|
||||
$o = '<b>' . t('Premium Channel App') . ' (' . t('Not Installed') . '):</b><br>';
|
||||
$o .= t('Allows you to set restrictions and terms on those that connect with your channel');
|
||||
return $o;
|
||||
}
|
||||
|
||||
$edit = ((local_channel() && (local_channel() == $channel_id)) ? true : false);
|
||||
|
||||
$text = get_pconfig($channel_id,'system','selltext');
|
||||
|
||||
@@ -34,7 +34,7 @@ class Connections extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
nav_set_selected('Connections');
|
||||
|
||||
|
||||
$active = false;
|
||||
$blocked = false;
|
||||
$hidden = false;
|
||||
@@ -127,6 +127,20 @@ class Connections extends \Zotlabs\Web\Controller {
|
||||
$unblocked = true;
|
||||
}
|
||||
|
||||
switch($_REQUEST['order']) {
|
||||
case 'name_desc':
|
||||
$sql_order = 'xchan_name DESC';
|
||||
break;
|
||||
case 'connected':
|
||||
$sql_order = 'abook_created';
|
||||
break;
|
||||
case 'connected_desc':
|
||||
$sql_order = 'abook_created DESC';
|
||||
break;
|
||||
default:
|
||||
$sql_order = 'xchan_name';
|
||||
}
|
||||
|
||||
$search = ((x($_REQUEST,'search')) ? notags(trim($_REQUEST['search'])) : '');
|
||||
|
||||
$tabs = array(
|
||||
@@ -233,7 +247,7 @@ class Connections extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash
|
||||
WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra $sql_extra2 ORDER BY xchan_name LIMIT %d OFFSET %d ",
|
||||
WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra $sql_extra2 ORDER BY $sql_order LIMIT %d OFFSET %d ",
|
||||
intval(local_channel()),
|
||||
intval(App::$pager['itemspage']),
|
||||
intval(App::$pager['start'])
|
||||
@@ -269,6 +283,28 @@ class Connections extends \Zotlabs\Web\Controller {
|
||||
if(! intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_comments'))) {
|
||||
$oneway = true;
|
||||
}
|
||||
|
||||
$perminfo['connpermcount']=0;
|
||||
$perminfo['connperms']=t('Accepts').': ';
|
||||
if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_comments'))) {
|
||||
$perminfo['connpermcount']++;
|
||||
$perminfo['connperms'] .= t('Comments');
|
||||
}
|
||||
if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','send_stream'))) {
|
||||
$perminfo['connpermcount']++;
|
||||
$perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
|
||||
$perminfo['connperms'] .= t('Stream items');
|
||||
}
|
||||
if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_wall'))) {
|
||||
$perminfo['connpermcount']++;
|
||||
$perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
|
||||
$perminfo['connperms'] .= t('Wall posts');
|
||||
}
|
||||
|
||||
if ($perminfo['connpermcount'] == 0) {
|
||||
$perminfo['connperms'] .= t('Nothing');
|
||||
}
|
||||
|
||||
|
||||
foreach($status as $str) {
|
||||
if(!$str)
|
||||
@@ -307,8 +343,12 @@ class Connections extends \Zotlabs\Web\Controller {
|
||||
'ignore_hover' => t('Ignore connection'),
|
||||
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
|
||||
'recent_label' => t('Recent activity'),
|
||||
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']),
|
||||
'oneway' => $oneway
|
||||
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
|
||||
'oneway' => $oneway,
|
||||
'perminfo' => $perminfo,
|
||||
'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''),
|
||||
'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0',
|
||||
'connect_hover' => t('Connect at this location')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -329,7 +369,7 @@ class Connections extends \Zotlabs\Web\Controller {
|
||||
killme();
|
||||
}
|
||||
else {
|
||||
$o .= "<script> var page_query = '" . escape_tags($_GET['q']) . "'; var extra_args = '" . extra_query_args() . "' ; </script>";
|
||||
$o .= "<script> var page_query = '" . escape_tags(urlencode($_GET['q'])) . "'; var extra_args = '" . extra_query_args() . "' ; </script>";
|
||||
$o .= replace_macros(get_markup_template('connections.tpl'),array(
|
||||
'$header' => t('Connections') . (($head) ? ': ' . $head : ''),
|
||||
'$tabs' => $tabs,
|
||||
|
||||
@@ -7,8 +7,16 @@ namespace Zotlabs\Module;
|
||||
*
|
||||
*/
|
||||
|
||||
use App;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Access\PermissionLimits;
|
||||
use Zotlabs\Web\HTTPHeaders;
|
||||
use Zotlabs\Lib\Permcat;
|
||||
|
||||
require_once('include/socgraph.php');
|
||||
require_once('include/selectors.php');
|
||||
@@ -16,7 +24,7 @@ require_once('include/group.php');
|
||||
require_once('include/photos.php');
|
||||
|
||||
|
||||
class Connedit extends \Zotlabs\Web\Controller {
|
||||
class Connedit extends Controller {
|
||||
|
||||
/* @brief Initialize the connection-editor
|
||||
*
|
||||
@@ -36,12 +44,12 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
intval(argv(1))
|
||||
);
|
||||
if($r) {
|
||||
\App::$poi = array_shift($r);
|
||||
App::$poi = array_shift($r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$channel = \App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
if($channel)
|
||||
head_set_icon($channel['xchan_photo_s']);
|
||||
|
||||
@@ -61,7 +69,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
if(! $contact_id)
|
||||
return;
|
||||
|
||||
$channel = \App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
|
||||
// TODO if configured for hassle-free permissions, we'll post the form with ajax as soon as the
|
||||
// connection enable is toggled to a special autopost url and set permissions immediately, leaving
|
||||
@@ -140,7 +148,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
$rating_text = trim(escape_tags($_REQUEST['rating_text']));
|
||||
|
||||
$all_perms = \Zotlabs\Access\Permissions::Perms();
|
||||
$all_perms = Permissions::Perms();
|
||||
|
||||
if($all_perms) {
|
||||
foreach($all_perms as $perm => $desc) {
|
||||
@@ -212,7 +220,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
$record = $z[0]['xlink_id'];
|
||||
}
|
||||
if($record) {
|
||||
\Zotlabs\Daemon\Master::Summon(array('Ratenotif','rating',$record));
|
||||
Master::Summon(array('Ratenotif','rating',$record));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +235,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
// request. The workaround is to approve the connection, then go back and
|
||||
// adjust permissions as desired.
|
||||
|
||||
$p = \Zotlabs\Access\Permissions::connect_perms(local_channel());
|
||||
$p = Permissions::connect_perms(local_channel());
|
||||
$my_perms = $p['perms'];
|
||||
if($my_perms) {
|
||||
foreach($my_perms as $k => $v) {
|
||||
@@ -257,12 +265,12 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
else
|
||||
notice( t('Failed to update connection record.') . EOL);
|
||||
|
||||
if(! intval(\App::$poi['abook_self'])) {
|
||||
if(! intval(App::$poi['abook_self'])) {
|
||||
if($new_friend) {
|
||||
\Zotlabs\Daemon\Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] );
|
||||
Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] );
|
||||
}
|
||||
|
||||
\Zotlabs\Daemon\Master::Summon( [
|
||||
Master::Summon( [
|
||||
'Notifier',
|
||||
(($new_friend) ? 'permission_create' : 'permission_update'),
|
||||
$contact_id
|
||||
@@ -275,7 +283,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
require_once('include/group.php');
|
||||
$g = group_rec_byhash(local_channel(),$default_group);
|
||||
if($g)
|
||||
group_add_member(local_channel(),'',\App::$poi['abook_xchan'],$g['id']);
|
||||
group_add_member(local_channel(),'',App::$poi['abook_xchan'],$g['id']);
|
||||
}
|
||||
|
||||
// Check if settings permit ("post new friend activity" is allowed, and
|
||||
@@ -286,8 +294,8 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if(($pr) && (! intval($orig_record[0]['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'],'system','post_newfriend')))) {
|
||||
$xarr = array();
|
||||
$xarr['verb'] = ACTIVITY_FRIEND;
|
||||
$xarr = [];
|
||||
|
||||
$xarr['item_wall'] = 1;
|
||||
$xarr['item_origin'] = 1;
|
||||
$xarr['item_thread_top'] = 1;
|
||||
@@ -297,21 +305,10 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
$xarr['deny_cid'] = $channel['channel_deny_cid'];
|
||||
$xarr['deny_gid'] = $channel['channel_deny_gid'];
|
||||
$xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0);
|
||||
$obj = array(
|
||||
'type' => ACTIVITY_OBJ_PERSON,
|
||||
'title' => \App::$poi['xchan_name'],
|
||||
'id' => \App::$poi['xchan_hash'],
|
||||
'link' => array(
|
||||
array('rel' => 'alternate', 'type' => 'text/html', 'href' => \App::$poi['xchan_url']),
|
||||
array('rel' => 'photo', 'type' => \App::$poi['xchan_photo_mimetype'], 'href' => \App::$poi['xchan_photo_l'])
|
||||
),
|
||||
);
|
||||
$xarr['obj'] = json_encode($obj);
|
||||
$xarr['obj_type'] = ACTIVITY_OBJ_PERSON;
|
||||
|
||||
$xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . \App::$poi['xchan_url'] . ']' . \App::$poi['xchan_name'] . '[/zrl]';
|
||||
$xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]';
|
||||
|
||||
$xarr['body'] .= "\n\n\n" . '[zrl=' . \App::$poi['xchan_url'] . '][zmg=80x80]' . \App::$poi['xchan_photo_m'] . '[/zmg][/zrl]';
|
||||
$xarr['body'] .= "\n\n\n" . '[zrl=' . App::$poi['xchan_url'] . '][zmg=80x80]' . App::$poi['xchan_photo_m'] . '[/zmg][/zrl]';
|
||||
|
||||
post_activity_item($xarr);
|
||||
|
||||
@@ -319,7 +316,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
// pull in a bit of content if there is any to pull in
|
||||
\Zotlabs\Daemon\Master::Summon(array('Onepoll',$contact_id));
|
||||
Master::Summon(array('Onepoll',$contact_id));
|
||||
|
||||
}
|
||||
|
||||
@@ -332,11 +329,11 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
intval($contact_id)
|
||||
);
|
||||
if($r) {
|
||||
\App::$poi = $r[0];
|
||||
App::$poi = $r[0];
|
||||
}
|
||||
|
||||
if($new_friend) {
|
||||
$arr = array('channel_id' => local_channel(), 'abook' => \App::$poi);
|
||||
$arr = array('channel_id' => local_channel(), 'abook' => App::$poi);
|
||||
call_hooks('accept_follow', $arr);
|
||||
}
|
||||
|
||||
@@ -356,23 +353,23 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
function connedit_clone(&$a) {
|
||||
|
||||
if(! \App::$poi)
|
||||
if(! App::$poi)
|
||||
return;
|
||||
|
||||
|
||||
$channel = \App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
|
||||
$r = q("SELECT abook.*, xchan.*
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d and abook_id = %d LIMIT 1",
|
||||
intval(local_channel()),
|
||||
intval(\App::$poi['abook_id'])
|
||||
intval(App::$poi['abook_id'])
|
||||
);
|
||||
if($r) {
|
||||
\App::$poi = array_shift($r);
|
||||
App::$poi = array_shift($r);
|
||||
}
|
||||
|
||||
$clone = \App::$poi;
|
||||
$clone = App::$poi;
|
||||
|
||||
unset($clone['abook_id']);
|
||||
unset($clone['abook_account']);
|
||||
@@ -382,7 +379,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
if($abconfig)
|
||||
$clone['abconfig'] = $abconfig;
|
||||
|
||||
build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
|
||||
Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
|
||||
}
|
||||
|
||||
/* @brief Generate content of connection edit page
|
||||
@@ -401,11 +398,11 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
$section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : '');
|
||||
$channel = \App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
|
||||
$yes_no = array(t('No'),t('Yes'));
|
||||
|
||||
$connect_perms = \Zotlabs\Access\Permissions::connect_perms(local_channel());
|
||||
$connect_perms = Permissions::connect_perms(local_channel());
|
||||
|
||||
$o .= "<script>function connectDefaultShare() {
|
||||
\$('.abook-edit-me').each(function() {
|
||||
@@ -426,7 +423,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
|
||||
$cmd = argv(2);
|
||||
|
||||
|
||||
$orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_id = %d AND abook_channel = %d AND abook_self = 0 LIMIT 1",
|
||||
intval($contact_id),
|
||||
@@ -440,7 +437,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
if($cmd === 'update') {
|
||||
// pull feed and consume it, which should subscribe to the hub.
|
||||
\Zotlabs\Daemon\Master::Summon(array('Poller',$contact_id));
|
||||
Master::Summon(array('Poller',$contact_id));
|
||||
goaway(z_root() . '/connedit/' . $contact_id);
|
||||
|
||||
}
|
||||
@@ -450,7 +447,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
$recurse = 0;
|
||||
$x = z_fetch_url(zid($url),false,$recurse,['session' => true]);
|
||||
if($x['success']) {
|
||||
$h = new \Zotlabs\Web\HTTPHeaders($x['header']);
|
||||
$h = new HTTPHeaders($x['header']);
|
||||
$fields = $h->fetch();
|
||||
if($fields) {
|
||||
foreach($fields as $y) {
|
||||
@@ -481,17 +478,17 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
if($cmd === 'refresh') {
|
||||
if($orig_record[0]['xchan_network'] === 'zot') {
|
||||
if(! zot_refresh($orig_record[0],\App::get_channel()))
|
||||
if(! zot_refresh($orig_record[0],App::get_channel()))
|
||||
notice( t('Refresh failed - channel is currently unavailable.') );
|
||||
}
|
||||
elseif($orig_record[0]['xchan_network'] === 'zot6') {
|
||||
if(! Libzot::refresh($orig_record[0],\App::get_channel()))
|
||||
if(! Libzot::refresh($orig_record[0],App::get_channel()))
|
||||
notice( t('Refresh failed - channel is currently unavailable.') );
|
||||
}
|
||||
else {
|
||||
|
||||
// if you are on a different network we'll force a refresh of the connection basic info
|
||||
\Zotlabs\Daemon\Master::Summon(array('Notifier','permission_update',$contact_id));
|
||||
Master::Summon(array('Notifier','permission_update',$contact_id));
|
||||
}
|
||||
goaway(z_root() . '/connedit/' . $contact_id);
|
||||
}
|
||||
@@ -549,16 +546,11 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
if($cmd === 'drop') {
|
||||
|
||||
|
||||
// @FIXME
|
||||
// We need to send either a purge or a refresh packet to the other side (the channel being unfriended).
|
||||
// The issue is that the abook DB record _may_ get destroyed when we call contact_remove. As the notifier
|
||||
// runs in the background there could be a race condition preventing this packet from being sent in all
|
||||
// cases.
|
||||
// PLACEHOLDER
|
||||
|
||||
contact_remove(local_channel(), $orig_record[0]['abook_id']);
|
||||
build_sync_packet(0 /* use the current local_channel */,
|
||||
|
||||
Master::Summon( [ 'Notifier', 'purge', local_channel(), $orig_record[0]['xchan_hash'] ] );
|
||||
|
||||
Libsync::build_sync_packet(0 /* use the current local_channel */,
|
||||
array('abook' => array(array(
|
||||
'abook_xchan' => $orig_record[0]['abook_xchan'],
|
||||
'entry_deleted' => true))
|
||||
@@ -573,13 +565,13 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
if(\App::$poi) {
|
||||
if(App::$poi) {
|
||||
|
||||
$abook_prev = 0;
|
||||
$abook_next = 0;
|
||||
|
||||
$contact_id = \App::$poi['abook_id'];
|
||||
$contact = \App::$poi;
|
||||
$contact_id = App::$poi['abook_id'];
|
||||
$contact = App::$poi;
|
||||
|
||||
$cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name",
|
||||
intval(local_channel())
|
||||
@@ -787,9 +779,9 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
$perms = array();
|
||||
$channel = \App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
|
||||
$global_perms = \Zotlabs\Access\Permissions::Perms();
|
||||
$global_perms = Permissions::Perms();
|
||||
|
||||
$existing = get_all_perms(local_channel(),$contact['abook_xchan'],false);
|
||||
|
||||
@@ -821,7 +813,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
$thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k);
|
||||
//fixme
|
||||
|
||||
$checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k);
|
||||
$checkinherited = PermissionLimits::Get(local_channel(),$k);
|
||||
|
||||
// For auto permissions (when $self is true) we don't want to look at existing
|
||||
// permissions because they are enabled for the channel owner
|
||||
@@ -834,7 +826,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
$perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited);
|
||||
}
|
||||
|
||||
$pcat = new \Zotlabs\Lib\Permcat(local_channel());
|
||||
$pcat = new Permcat(local_channel());
|
||||
$pcatlist = $pcat->listing();
|
||||
$permcats = [];
|
||||
if($pcatlist) {
|
||||
@@ -848,7 +840,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
$locstr = unpunify($contact['xchan_url']);
|
||||
|
||||
$clone_warn = '';
|
||||
$clonable = (in_array($contact['xchan_network'],['zot','rss']) ? true : false);
|
||||
$clonable = (in_array($contact['xchan_network'],['zot', 'zot6', 'rss']) ? true : false);
|
||||
if(! $clonable) {
|
||||
$clone_warn = '<strong>';
|
||||
$clone_warn .= ((intval($contact['abook_not_here']))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
/*
|
||||
@file cover_photo.php
|
||||
@brief Module-file with functions for handling of cover-photos
|
||||
@@ -48,6 +50,32 @@ class Cover_photo extends \Zotlabs\Web\Controller {
|
||||
$channel = \App::get_channel();
|
||||
|
||||
check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo');
|
||||
|
||||
// Remove cover photo
|
||||
if(isset($_POST['remove'])) {
|
||||
|
||||
$r = q("SELECT resource_id FROM photo WHERE photo_usage = %d AND uid = %d LIMIT 1",
|
||||
intval(PHOTO_COVER),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if($r) {
|
||||
q("update photo set photo_usage = %d where photo_usage = %d and uid = %d",
|
||||
intval(PHOTO_NORMAL),
|
||||
intval(PHOTO_COVER),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
$sync = attach_export_data($channel,$r[0]['resource_id']);
|
||||
if($sync)
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
}
|
||||
|
||||
// Update directory in background
|
||||
\Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id']));
|
||||
|
||||
goaway(z_root() . '/cover_photo');
|
||||
}
|
||||
|
||||
if((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) {
|
||||
|
||||
@@ -106,7 +134,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
|
||||
if(file_exists($tmp_name)) {
|
||||
$base_image = $r[0];
|
||||
$gis = getimagesize($tmp_name);
|
||||
logger('gis: ' . print_r($gis,true));
|
||||
logger('gis: ' . print_r($gis,true), LOGGER_DEBUG);
|
||||
$base_image['width'] = $gis[0];
|
||||
$base_image['height'] = $gis[1];
|
||||
$base_image['content'] = @file_get_contents($tmp_name);
|
||||
@@ -167,25 +195,18 @@ logger('gis: ' . print_r($gis,true));
|
||||
'filename' => $base_image['filename'],
|
||||
'album' => t('Cover Photos'),
|
||||
'os_path' => $base_image['os_path'],
|
||||
'display_path' => $base_image['display_path']
|
||||
'display_path' => $base_image['display_path'],
|
||||
'photo_usage' => PHOTO_COVER
|
||||
];
|
||||
|
||||
$p['imgscale'] = 7;
|
||||
$p['photo_usage'] = PHOTO_COVER;
|
||||
|
||||
$r1 = $im->save($p);
|
||||
|
||||
$r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200);
|
||||
|
||||
$im->doScaleImage(850,310);
|
||||
$p['imgscale'] = 8;
|
||||
|
||||
$r2 = $im->save($p);
|
||||
|
||||
$r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850);
|
||||
|
||||
$im->doScaleImage(425,160);
|
||||
$p['imgscale'] = 9;
|
||||
|
||||
$r3 = $im->save($p);
|
||||
|
||||
$r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425);
|
||||
|
||||
if($r1 === false || $r2 === false || $r3 === false) {
|
||||
// if one failed, delete them all so we can start over.
|
||||
notice( t('Image resize failed.') . EOL );
|
||||
@@ -193,13 +214,28 @@ logger('gis: ' . print_r($gis,true));
|
||||
dbesc($base_image['resource_id']),
|
||||
local_channel()
|
||||
);
|
||||
|
||||
$x = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1 AND imgscale >= 7",
|
||||
dbesc($base_image['resource_id']),
|
||||
local_channel()
|
||||
);
|
||||
if($x) {
|
||||
foreach($x as $xx) {
|
||||
@unlink(dbunescbin($xx['content']));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
$this->send_cover_photo_activity($channel,$base_image,$profile);
|
||||
|
||||
|
||||
|
||||
$sync = attach_export_data($channel,$base_image['resource_id']);
|
||||
if($sync)
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
|
||||
// Update directory in background
|
||||
\Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id']));
|
||||
}
|
||||
else
|
||||
notice( t('Unable to process image') . EOL);
|
||||
@@ -215,7 +251,7 @@ logger('gis: ' . print_r($gis,true));
|
||||
|
||||
require_once('include/attach.php');
|
||||
|
||||
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash));
|
||||
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash, 'nosync' => true));
|
||||
|
||||
logger('attach_store: ' . print_r($res,true));
|
||||
|
||||
@@ -257,14 +293,6 @@ logger('gis: ' . print_r($gis,true));
|
||||
$arr['item_thread_top'] = 1;
|
||||
$arr['item_origin'] = 1;
|
||||
$arr['item_wall'] = 1;
|
||||
$arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
|
||||
$arr['verb'] = ACTIVITY_UPDATE;
|
||||
|
||||
$arr['obj'] = json_encode(array(
|
||||
'type' => $arr['obj_type'],
|
||||
'id' => z_root() . '/photo/' . $photo['resource_id'] . '-7',
|
||||
'link' => array('rel' => 'photo', 'type' => $photo['mimetype'], 'href' => z_root() . '/photo/' . $photo['resource_id'] . '-7')
|
||||
));
|
||||
|
||||
if($profile && stripos($profile['gender'],t('female')) !== false)
|
||||
$t = t('%1$s updated her %2$s');
|
||||
@@ -393,6 +421,7 @@ logger('gis: ' . print_r($gis,true));
|
||||
'$lbl_profiles' => t('Select a profile:'),
|
||||
'$title' => t('Change Cover Photo'),
|
||||
'$submit' => t('Upload'),
|
||||
'$remove' => t('Remove'),
|
||||
'$profiles' => $profiles,
|
||||
'$embedPhotos' => t('Use a photo from your albums'),
|
||||
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use \Sabre\DAV as SDAV;
|
||||
use \Zotlabs\Storage;
|
||||
use Sabre\DAV as SDAV;
|
||||
use Zotlabs\Storage;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
require_once('include/attach.php');
|
||||
require_once('include/auth.php');
|
||||
@@ -46,15 +47,16 @@ class Dav extends \Zotlabs\Web\Controller {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
if($sigblock) {
|
||||
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
||||
if($keyId) {
|
||||
$r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
|
||||
$r = q("select * from hubloc where hubloc_addr = '%s'",
|
||||
dbesc($keyId)
|
||||
);
|
||||
if($r) {
|
||||
$c = channelx_by_hash($r[0]['hubloc_hash']);
|
||||
$r = Libzot::zot_record_preferred($r);
|
||||
$c = channelx_by_hash($r['hubloc_hash']);
|
||||
if($c) {
|
||||
$a = q("select * from account where account_id = %d limit 1",
|
||||
intval($c['channel_account_id'])
|
||||
@@ -69,7 +71,7 @@ class Dav extends \Zotlabs\Web\Controller {
|
||||
continue;
|
||||
|
||||
if($record) {
|
||||
$verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
|
||||
$verified = HTTPSig::verify('',$record['channel']['channel_pubkey']);
|
||||
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
|
||||
$record = null;
|
||||
}
|
||||
@@ -94,6 +96,8 @@ class Dav extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
$auth = new \Zotlabs\Storage\BasicAuth();
|
||||
// $auth->observer = get_observer_hash();
|
||||
|
||||
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
|
||||
|
||||
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Zotlabs\Module;
|
||||
use App;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
require_once('include/socgraph.php');
|
||||
require_once('include/selectors.php');
|
||||
@@ -164,7 +165,7 @@ class Defperms extends Controller {
|
||||
if($abconfig)
|
||||
$clone['abconfig'] = $abconfig;
|
||||
|
||||
build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
|
||||
Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
|
||||
}
|
||||
|
||||
/* @brief Generate content of connection default permissions page
|
||||
|
||||
52
Zotlabs/Module/Dircensor.php
Normal file
52
Zotlabs/Module/Dircensor.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
|
||||
class Dircensor extends Controller {
|
||||
|
||||
function get() {
|
||||
if(! is_site_admin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$dirmode = intval(get_config('system','directory_mode'));
|
||||
|
||||
if (! ($dirmode == DIRECTORY_MODE_PRIMARY || $dirmode == DIRECTORY_MODE_STANDALONE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$xchan = argv(1);
|
||||
if(! $xchan) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = q("select * from xchan where xchan_hash = '%s'",
|
||||
dbesc($xchan)
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
return;
|
||||
}
|
||||
|
||||
$val = (($r[0]['xchan_censored']) ? 0 : 1);
|
||||
|
||||
q("update xchan set xchan_censored = $val where xchan_hash = '%s'",
|
||||
dbesc($xchan)
|
||||
);
|
||||
|
||||
if($val) {
|
||||
info( t('Entry censored') . EOL);
|
||||
}
|
||||
else {
|
||||
info( t('Entry uncensored') . EOL);
|
||||
}
|
||||
|
||||
goaway(z_root() . '/directory');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,15 +2,19 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
require_once('include/socgraph.php');
|
||||
require_once('include/dir_fns.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
|
||||
class Directory extends \Zotlabs\Web\Controller {
|
||||
class Directory extends Controller {
|
||||
|
||||
function init() {
|
||||
\App::set_pager_itemspage(60);
|
||||
App::set_pager_itemspage(30);
|
||||
|
||||
if(local_channel() && x($_GET,'ignore')) {
|
||||
q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ",
|
||||
@@ -21,7 +25,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if(local_channel())
|
||||
\App::$profile_uid = local_channel();
|
||||
App::$profile_uid = local_channel();
|
||||
|
||||
$observer = get_observer_hash();
|
||||
$global_changed = false;
|
||||
@@ -103,8 +107,14 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
$suggest = (local_channel() && x($_REQUEST,'suggest')) ? $_REQUEST['suggest'] : '';
|
||||
|
||||
if($suggest) {
|
||||
|
||||
$r = suggestion_query(local_channel(),get_observer_hash());
|
||||
|
||||
// the directory options have no effect in suggestion mode
|
||||
|
||||
$globaldir = 1;
|
||||
$safe_mode = 1;
|
||||
$type = 0;
|
||||
|
||||
$r = suggestion_query(local_channel(),get_observer_hash(),0,60);
|
||||
|
||||
if(! $r) {
|
||||
notice( t('No default suggestions were found.') . EOL);
|
||||
@@ -134,9 +144,15 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
|
||||
$dirmode = intval(get_config('system','directory_mode'));
|
||||
|
||||
$directory_admin = false;
|
||||
|
||||
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
|
||||
$url = z_root() . '/dirsearch';
|
||||
}
|
||||
if (is_site_admin()) {
|
||||
$directory_admin = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(! $url) {
|
||||
$directory = find_upstream_directory($dirmode);
|
||||
if((! $directory) || (! array_key_exists('url',$directory)) || (! $directory['url']))
|
||||
@@ -176,7 +192,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
$query .= '&t=' . $token;
|
||||
|
||||
if(! $globaldir)
|
||||
$query .= '&hub=' . \App::get_hostname();
|
||||
$query .= '&hub=' . App::get_hostname();
|
||||
|
||||
if($search)
|
||||
$query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search);
|
||||
@@ -198,8 +214,8 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
if($sort_order)
|
||||
$query .= '&order=' . urlencode($sort_order);
|
||||
|
||||
if(\App::$pager['page'] != 1)
|
||||
$query .= '&p=' . \App::$pager['page'];
|
||||
if(App::$pager['page'] != 1)
|
||||
$query .= '&p=' . App::$pager['page'];
|
||||
|
||||
logger('mod_directory: query: ' . $query);
|
||||
|
||||
@@ -212,12 +228,17 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
if($j) {
|
||||
|
||||
if($j['results']) {
|
||||
|
||||
|
||||
$results = $j['results'];
|
||||
if($suggest) {
|
||||
$results = self::reorder_results($results,$addresses);
|
||||
}
|
||||
|
||||
$entries = array();
|
||||
|
||||
$photo = 'thumb';
|
||||
|
||||
foreach($j['results'] as $rr) {
|
||||
foreach($results as $rr) {
|
||||
|
||||
$profile_link = chanlink_url($rr['url']);
|
||||
|
||||
@@ -272,12 +293,15 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
$marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital']: False);
|
||||
|
||||
$homepage = ((x($profile,'homepage') == 1) ? t('Homepage: ') : False);
|
||||
$homepageurl = ((x($profile,'homepage') == 1) ? $profile['homepage'] : '');
|
||||
$homepageurl = ((x($profile,'homepage') == 1) ? html2plain($profile['homepage']) : '');
|
||||
|
||||
$hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
|
||||
|
||||
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False);
|
||||
$hometown = ((x($profile,'hometown') == 1) ? html2plain($profile['hometown']) : False);
|
||||
|
||||
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False);
|
||||
if ($about && $safe_mode) {
|
||||
$about = html2plain($about);
|
||||
}
|
||||
|
||||
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
|
||||
|
||||
|
||||
@@ -332,9 +356,11 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
'canrate' => (($rating_enabled && local_channel()) ? true : false),
|
||||
'pdesc' => $pdesc,
|
||||
'pdesc_label' => t('Description:'),
|
||||
'censor' => (($directory_admin) ? 'dircensor/' . $rr['hash'] : ''),
|
||||
'censor_label' => (($rr['censored']) ? t('Uncensor') : t('Censor')),
|
||||
'marital' => $marital,
|
||||
'homepage' => $homepage,
|
||||
'homepageurl' => linkify($homepageurl),
|
||||
'homepageurl' => (($safe_mode) ? $homepageurl : linkify($homepageurl)),
|
||||
'hometown' => $hometown,
|
||||
'hometown_label' => t('Hometown:'),
|
||||
'about' => $about,
|
||||
@@ -376,7 +402,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
ksort($entries); // Sort array by key so that foreach-constructs work as expected
|
||||
|
||||
if($j['keywords']) {
|
||||
\App::$data['directory_keywords'] = $j['keywords'];
|
||||
App::$data['directory_keywords'] = $j['keywords'];
|
||||
}
|
||||
|
||||
logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA);
|
||||
@@ -399,7 +425,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
|
||||
$dirtitle = (($globaldir) ? t('Global Directory') : t('Local Directory'));
|
||||
|
||||
$o .= "<script> var page_query = '" . escape_tags($_GET['q']) . "'; var extra_args = '" . extra_query_args() . "' ; divmore_height = " . intval($maxheight) . "; </script>";
|
||||
$o .= "<script> var page_query = '" . escape_tags(urlencode($_GET['q'])) . "'; var extra_args = '" . extra_query_args() . "' ; divmore_height = " . intval($maxheight) . "; </script>";
|
||||
$o .= replace_macros($tpl, array(
|
||||
'$search' => $search,
|
||||
'$desc' => t('Find'),
|
||||
@@ -427,7 +453,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
echo $o;
|
||||
killme();
|
||||
}
|
||||
if(\App::$pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) {
|
||||
if(App::$pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) {
|
||||
goaway(z_root() . '/chanview/?f=&address=' . $search);
|
||||
}
|
||||
info( t("No entries (some entries may be hidden).") . EOL);
|
||||
@@ -438,5 +464,22 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
static public function reorder_results($results,$suggests) {
|
||||
|
||||
if(! $suggests)
|
||||
return $results;
|
||||
|
||||
$out = [];
|
||||
foreach($suggests as $k => $v) {
|
||||
foreach($results as $rv) {
|
||||
if($k == $rv['address']) {
|
||||
$out[intval($v)] = $rv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
require_once('include/dir_fns.php');
|
||||
|
||||
|
||||
|
||||
class Dirsearch extends \Zotlabs\Web\Controller {
|
||||
class Dirsearch extends Controller {
|
||||
|
||||
function init() {
|
||||
\App::set_pager_itemspage(60);
|
||||
App::set_pager_itemspage(30);
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +28,8 @@ class Dirsearch extends \Zotlabs\Web\Controller {
|
||||
$ret['message'] = t('This site is not a directory server');
|
||||
json_return_and_die($ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$access_token = $_REQUEST['t'];
|
||||
|
||||
$token = get_config('system','realm_token');
|
||||
@@ -116,12 +120,12 @@ class Dirsearch extends \Zotlabs\Web\Controller {
|
||||
$sql_extra .= $this->dir_query_build($joiner,'xchan_name',$name);
|
||||
if($address)
|
||||
$sql_extra .= $this->dir_query_build($joiner,'xchan_addr',$address);
|
||||
if($city)
|
||||
$sql_extra .= $this->dir_query_build($joiner,'xprof_locale',$city);
|
||||
if($locale)
|
||||
$sql_extra .= $this->dir_query_build($joiner,'xprof_locale',$locale);
|
||||
if($region)
|
||||
$sql_extra .= $this->dir_query_build($joiner,'xprof_region',$region);
|
||||
if($post)
|
||||
$sql_extra .= $this->dir_query_build($joiner,'xprof_postcode',$post);
|
||||
if($postcode)
|
||||
$sql_extra .= $this->dir_query_build($joiner,'xprof_postcode',$postcode);
|
||||
if($country)
|
||||
$sql_extra .= $this->dir_query_build($joiner,'xprof_country',$country);
|
||||
if($gender)
|
||||
@@ -286,29 +290,29 @@ class Dirsearch extends \Zotlabs\Web\Controller {
|
||||
else
|
||||
$entry['total_ratings'] = 0;
|
||||
|
||||
$entry['name'] = $rr['xchan_name'];
|
||||
$entry['hash'] = $rr['xchan_hash'];
|
||||
|
||||
$entry['name'] = $rr['xchan_name'];
|
||||
$entry['hash'] = $rr['xchan_hash'];
|
||||
$entry['censored'] = $rr['xchan_censored'];
|
||||
$entry['selfcensored'] = $rr['xchan_selfcensored'];
|
||||
$entry['public_forum'] = (intval($rr['xchan_pubforum']) ? true : false);
|
||||
|
||||
$entry['url'] = $rr['xchan_url'];
|
||||
$entry['photo_l'] = $rr['xchan_photo_l'];
|
||||
$entry['photo'] = $rr['xchan_photo_m'];
|
||||
$entry['address'] = $rr['xchan_addr'];
|
||||
$entry['description'] = $rr['xprof_desc'];
|
||||
$entry['locale'] = $rr['xprof_locale'];
|
||||
$entry['region'] = $rr['xprof_region'];
|
||||
$entry['postcode'] = $rr['xprof_postcode'];
|
||||
$entry['country'] = $rr['xprof_country'];
|
||||
$entry['birthday'] = $rr['xprof_dob'];
|
||||
$entry['age'] = $rr['xprof_age'];
|
||||
$entry['gender'] = $rr['xprof_gender'];
|
||||
$entry['marital'] = $rr['xprof_marital'];
|
||||
$entry['sexual'] = $rr['xprof_sexual'];
|
||||
$entry['about'] = $rr['xprof_about'];
|
||||
$entry['homepage'] = $rr['xprof_homepage'];
|
||||
$entry['hometown'] = $rr['xprof_hometown'];
|
||||
$entry['keywords'] = $rr['xprof_keywords'];
|
||||
$entry['url'] = $rr['xchan_url'];
|
||||
$entry['photo_l'] = $rr['xchan_photo_l'];
|
||||
$entry['photo'] = $rr['xchan_photo_m'];
|
||||
$entry['address'] = $rr['xchan_addr'];
|
||||
$entry['description'] = $rr['xprof_desc'];
|
||||
$entry['locale'] = $rr['xprof_locale'];
|
||||
$entry['region'] = $rr['xprof_region'];
|
||||
$entry['postcode'] = $rr['xprof_postcode'];
|
||||
$entry['country'] = $rr['xprof_country'];
|
||||
$entry['birthday'] = $rr['xprof_dob'];
|
||||
$entry['age'] = $rr['xprof_age'];
|
||||
$entry['gender'] = $rr['xprof_gender'];
|
||||
$entry['marital'] = $rr['xprof_marital'];
|
||||
$entry['sexual'] = $rr['xprof_sexual'];
|
||||
$entry['about'] = $rr['xprof_about'];
|
||||
$entry['homepage'] = $rr['xprof_homepage'];
|
||||
$entry['hometown'] = $rr['xprof_hometown'];
|
||||
$entry['keywords'] = $rr['xprof_keywords'];
|
||||
|
||||
$entries[] = $entry;
|
||||
|
||||
@@ -394,7 +398,7 @@ class Dirsearch extends \Zotlabs\Web\Controller {
|
||||
$quoted_string = false;
|
||||
}
|
||||
else
|
||||
$curr['value'] .= ' ' . trim(q);
|
||||
$curr['value'] .= ' ' . trim($q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
$module_format = 'html';
|
||||
}
|
||||
|
||||
if($load)
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
|
||||
if(observer_prohibited()) {
|
||||
notice( t('Public access denied.') . EOL);
|
||||
return;
|
||||
@@ -47,7 +44,6 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
$observer_is_owner = false;
|
||||
$updateable = false;
|
||||
|
||||
if(local_channel() && (! $update)) {
|
||||
|
||||
@@ -101,7 +97,7 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
if($decoded)
|
||||
$item_hash = $decoded;
|
||||
|
||||
$r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid like '%s' limit 1",
|
||||
$r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid like '%s' limit 1",
|
||||
dbesc($item_hash . '%')
|
||||
);
|
||||
|
||||
@@ -159,14 +155,17 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
if($target_item['item_type'] == ITEM_TYPE_CARD) {
|
||||
|
||||
$x = q("select * from channel where channel_id = %d limit 1",
|
||||
intval($target_item['uid'])
|
||||
);
|
||||
|
||||
$y = q("select * from iconfig left join item on iconfig.iid = item.id
|
||||
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'CARD' and item.id = %d limit 1",
|
||||
intval($target_item['uid']),
|
||||
intval($target_item['parent'])
|
||||
);
|
||||
|
||||
if($x && $y) {
|
||||
goaway(z_root() . '/cards/' . $x[0]['channel_address'] . '/' . $y[0]['v']);
|
||||
}
|
||||
@@ -175,27 +174,22 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
if ($target_item['item_type'] == ITEM_TYPE_CUSTOM) {
|
||||
call_hooks('item_custom_display',$target_item);
|
||||
notice( t('Page not found.') . EOL);
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
|
||||
|
||||
$simple_update = (($update) ? " AND item_unseen = 1 " : '');
|
||||
|
||||
$simple_update = '';
|
||||
if($update && $_SESSION['loadtime'])
|
||||
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
|
||||
if($load)
|
||||
$simple_update = '';
|
||||
|
||||
if($static && $simple_update)
|
||||
$simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
|
||||
|
||||
if((! $update) && (! $load)) {
|
||||
|
||||
$static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1);
|
||||
if((! $update) && (! $load)) {
|
||||
|
||||
// if the target item is not a post (eg a like) we want to address its thread parent
|
||||
|
||||
$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
|
||||
//$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
|
||||
$mid = $target_item['mid'];
|
||||
|
||||
// if we got a decoded hash we must encode it again before handing to javascript
|
||||
if($decoded)
|
||||
@@ -218,9 +212,9 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
'$conv' => '0',
|
||||
'$spam' => '0',
|
||||
'$fh' => '0',
|
||||
'$dm' => '0',
|
||||
'$nouveau' => '0',
|
||||
'$wall' => '0',
|
||||
'$static' => $static,
|
||||
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
|
||||
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
|
||||
'$search' => '',
|
||||
@@ -233,7 +227,7 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
'$dbegin' => '',
|
||||
'$verb' => '',
|
||||
'$net' => '',
|
||||
'$mid' => $mid
|
||||
'$mid' => (($mid) ? urlencode($mid) : '')
|
||||
));
|
||||
|
||||
head_add_link([
|
||||
@@ -264,9 +258,6 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
intval(local_channel()),
|
||||
dbesc($target_item['parent_mid'])
|
||||
);
|
||||
if($r) {
|
||||
$updateable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(! $r) {
|
||||
@@ -308,11 +299,7 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
intval(local_channel()),
|
||||
dbesc($target_item['parent_mid'])
|
||||
);
|
||||
if($r) {
|
||||
$updateable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($r === null) {
|
||||
// in case somebody turned off public access to sys channel content using permissions
|
||||
// make that content unsearchable by ensuring the owner_xchan can't match
|
||||
@@ -332,7 +319,6 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
intval($sysid)
|
||||
);
|
||||
}
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
}
|
||||
|
||||
else {
|
||||
@@ -422,13 +408,6 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
if($updateable) {
|
||||
$x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ",
|
||||
intval(local_channel()),
|
||||
intval($r[0]['item_id'])
|
||||
);
|
||||
}
|
||||
|
||||
$o .= '<div id="content-complete"></div>';
|
||||
|
||||
@@ -452,6 +431,8 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
|
||||
}
|
||||
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
|
||||
return $o;
|
||||
|
||||
}
|
||||
|
||||
@@ -16,17 +16,20 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
$channel = \App::get_channel();
|
||||
|
||||
$mid = ((argc() > 1) ? argv(1) : '');
|
||||
$encoded_mid = '';
|
||||
|
||||
if(strpos($mid,'b64.') === 0)
|
||||
if(strpos($mid,'b64.') === 0) {
|
||||
$encoded_mid = $mid;
|
||||
$mid = @base64url_decode(substr($mid,4));
|
||||
|
||||
|
||||
}
|
||||
if($mid === 'push') {
|
||||
$table = 'push';
|
||||
$mid = ((argc() > 2) ? argv(2) : '');
|
||||
|
||||
if(strpos($mid,'b64.') === 0)
|
||||
if(strpos($mid,'b64.') === 0) {
|
||||
$encoded_mid = $mid;
|
||||
$mid = @base64url_decode(substr($mid,4));
|
||||
}
|
||||
|
||||
if($mid) {
|
||||
$i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ",
|
||||
@@ -40,7 +43,7 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
sleep(3);
|
||||
goaway(z_root() . '/dreport/' . urlencode($mid));
|
||||
goaway(z_root() . '/dreport/' . (($encoded_mid) ? $encoded_mid : $mid));
|
||||
}
|
||||
|
||||
if($mid === 'mail') {
|
||||
@@ -159,6 +162,7 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
'$title' => sprintf( t('Delivery report for %1$s'),basename($mid)) . '...',
|
||||
'$table' => $table,
|
||||
'$mid' => urlencode($mid),
|
||||
'$safe_mid' => urlencode(gen_link_id($mid)),
|
||||
'$options' => t('Options'),
|
||||
'$push' => t('Redeliver'),
|
||||
'$entries' => $entries
|
||||
|
||||
@@ -45,7 +45,8 @@ class Editpost extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($itm[0]['resource_type'] === 'event' && $itm[0]['resource_id']) {
|
||||
goaway(z_root() . '/events/' . $itm[0]['resource_id'] . '?expandform=1');
|
||||
goaway(z_root() . '/cdav/calendar/' . $itm[0]['resource_id']);
|
||||
//goaway(z_root() . '/events/' . $itm[0]['resource_id'] . '?expandform=1');
|
||||
}
|
||||
|
||||
$owner_uid = $itm[0]['uid'];
|
||||
|
||||
@@ -41,24 +41,46 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving link ' . $href, 'status' => false));
|
||||
}
|
||||
$resource_id = array_pop(explode('/', $href));
|
||||
$r = q("SELECT obj from item where resource_type = 'photo' and resource_id = '%s' limit 1",
|
||||
dbesc($resource_id)
|
||||
);
|
||||
if (!$r) {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
}
|
||||
$obj = json_decode($r[0]['obj'], true);
|
||||
if (x($obj, 'body')) {
|
||||
$photolink = $obj['body'];
|
||||
} elseif (x($obj, 'bbcode')) {
|
||||
$photolink = $obj['bbcode'];
|
||||
} else {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
}
|
||||
json_return_and_die(array('status' => true, 'photolink' => $photolink, 'resource_id' => $resource_id));
|
||||
$x = self::photolink($resource_id);
|
||||
if($x)
|
||||
json_return_and_die(array('status' => true, 'photolink' => $x, 'resource_id' => $resource_id));
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static function photolink($resource) {
|
||||
$channel = \App::get_channel();
|
||||
$output = EMPTY_STR;
|
||||
if($channel) {
|
||||
$resolution = ((feature_enabled($channel['channel_id'],'large_photos')) ? 1 : 2);
|
||||
$r = q("select mimetype, height, width from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1",
|
||||
dbesc($resource),
|
||||
intval($resolution),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if(! $r)
|
||||
return $output;
|
||||
|
||||
if($r[0]['mimetype'] === 'image/jpeg')
|
||||
$ext = '.jpg';
|
||||
elseif($r[0]['mimetype'] === 'image/png')
|
||||
$ext = '.png';
|
||||
elseif($r[0]['mimetype'] === 'image/gif')
|
||||
$ext = '.gif';
|
||||
elseif($r[0]['mimetype'] === 'image/webp')
|
||||
$exp = '.webp';
|
||||
else
|
||||
$ext = EMPTY_STR;
|
||||
|
||||
$output = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $resource . ']' .
|
||||
'[zmg=' . $r[0]['width'] . 'x' . $r[0]['height'] . ']' . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . '[/zmg][/zrl]';
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get photos from an album.
|
||||
*
|
||||
|
||||
76
Zotlabs/Module/Event.php
Normal file
76
Zotlabs/Module/Event.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\LDSignatures;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
class Event extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
if(ActivityStreams::is_as_request()) {
|
||||
$item_id = argv(1);
|
||||
|
||||
if(! $item_id)
|
||||
return;
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
|
||||
and item.item_delayed = 0 and item.item_blocked = 0 ";
|
||||
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
$r = q("select * from item where mid like '%s' $item_normal $sql_extra limit 1",
|
||||
dbesc(z_root() . '/activity/' . $item_id . '%')
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
$r = q("select * from item where mid like '%s' $item_normal limit 1",
|
||||
dbesc(z_root() . '/activity/' . $item_id . '%')
|
||||
);
|
||||
|
||||
if($r) {
|
||||
http_status_exit(403, 'Forbidden');
|
||||
}
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
xchan_query($r,true);
|
||||
$items = fetch_post_tags($r,true);
|
||||
|
||||
$channel = channelx_by_n($items[0]['uid']);
|
||||
|
||||
if(! is_array($items[0]['obj'])) {
|
||||
$obj = json_decode($items[0]['obj'],true);
|
||||
}
|
||||
else {
|
||||
$obj = $items[0]['obj'];
|
||||
}
|
||||
|
||||
$x = array_merge(['@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1',
|
||||
z_root() . ZOT_APSCHEMA_REV
|
||||
]], $obj );
|
||||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
|
||||
$x['signature'] = LDSignatures::sign($x,$channel);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
|
||||
HTTPSig::set_headers($h);
|
||||
|
||||
echo $ret;
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,9 @@ require_once('include/html2plain.php');
|
||||
class Events extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
// this module is deprecated
|
||||
return;
|
||||
|
||||
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
|
||||
|
||||
@@ -245,6 +248,9 @@ class Events extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
// this module is deprecated
|
||||
return;
|
||||
|
||||
if(argc() > 2 && argv(1) == 'ical') {
|
||||
$event_id = argv(2);
|
||||
@@ -662,9 +668,10 @@ class Events extends \Zotlabs\Web\Controller {
|
||||
'html'=>$html,
|
||||
'plink' => array($rr['plink'],t('Link to Source'),'',''),
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($export) {
|
||||
header('Content-type: text/calendar');
|
||||
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );
|
||||
|
||||
@@ -17,7 +17,7 @@ class Feed extends \Zotlabs\Web\Controller {
|
||||
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
|
||||
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
|
||||
$params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0);
|
||||
$params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 40);
|
||||
$params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 10);
|
||||
$params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
|
||||
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
|
||||
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 0);
|
||||
|
||||
79
Zotlabs/Module/Fhubloc_id_url.php
Normal file
79
Zotlabs/Module/Fhubloc_id_url.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
/* fix missing or hubloc_id_url entries */
|
||||
|
||||
class Fhubloc_id_url extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
if(! is_site_admin())
|
||||
return;
|
||||
|
||||
q("START TRANSACTION");
|
||||
|
||||
// remove broken xchan entries
|
||||
$r0 = dbq("DELETE FROM xchan WHERE xchan_hash = ''");
|
||||
|
||||
// remove broken hubloc entries
|
||||
$r1 = dbq("DELETE FROM hubloc WHERE hubloc_hash = ''");
|
||||
|
||||
// fix legacy zot hubloc_id_url
|
||||
$r2 = dbq("UPDATE hubloc
|
||||
SET hubloc_id_url = CONCAT(hubloc_url, '/channel/', SUBSTRING(hubloc_addr FROM 1 FOR POSITION('@' IN hubloc_addr) -1))
|
||||
WHERE hubloc_network = 'zot'
|
||||
AND hubloc_id_url = ''"
|
||||
);
|
||||
|
||||
// fix singleton networks hubloc_id_url
|
||||
if(ACTIVE_DBTYPE == DBTYPE_MYSQL) {
|
||||
// fix entries for activitypub which miss the xchan_url due to an earlier bug
|
||||
$r3 = dbq("UPDATE xchan
|
||||
SET xchan_url = xchan_hash
|
||||
WHERE xchan_network = 'activitypub'
|
||||
AND xchan_url = ''"
|
||||
);
|
||||
|
||||
$r4 = dbq("UPDATE hubloc
|
||||
LEFT JOIN xchan ON hubloc.hubloc_hash = xchan.xchan_hash
|
||||
SET hubloc.hubloc_id_url = xchan.xchan_url
|
||||
WHERE hubloc.hubloc_network IN ('activitypub', 'diaspora', 'friendica-over-diaspora', 'gnusoc')
|
||||
AND hubloc.hubloc_id_url = ''
|
||||
AND xchan.xchan_url IS NOT NULL"
|
||||
);
|
||||
|
||||
}
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
// fix entries for activitypub which miss the xchan_url due to an earlier bug
|
||||
$r3 = dbq("UPDATE xchan
|
||||
SET xchan_url = xchan_hash
|
||||
WHERE xchan_network = 'activitypub'
|
||||
AND xchan_url = ''"
|
||||
);
|
||||
|
||||
$r4 = dbq("UPDATE hubloc
|
||||
SET hubloc_id_url = xchan_url
|
||||
FROM xchan
|
||||
WHERE hubloc_hash = xchan_hash
|
||||
AND hubloc_network IN ('activitypub', 'diaspora', 'friendica-over-diaspora', 'gnusoc')
|
||||
AND hubloc_id_url = ''
|
||||
AND xchan_url IS NOT NULL"
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
if($r0 && $r1 && $r2 && $r3 && $r4) {
|
||||
// remove hubloc entries where hubloc_id_url could not be fixed
|
||||
$r5 = dbq("DELETE FROM hubloc WHERE hubloc_id_url = ''");
|
||||
}
|
||||
|
||||
if($r0 && $r1 && $r2 && $r3 && $r4 && $r5) {
|
||||
q("COMMIT");
|
||||
return 'Completed';
|
||||
}
|
||||
|
||||
q("ROLLBACK");
|
||||
return 'Failed';
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/crypto.php');
|
||||
|
||||
@@ -10,7 +12,7 @@ require_once('include/crypto.php');
|
||||
class Fhublocs extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
|
||||
if(! is_site_admin())
|
||||
return;
|
||||
|
||||
@@ -21,9 +23,11 @@ class Fhublocs extends \Zotlabs\Web\Controller {
|
||||
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
|
||||
$found = false;
|
||||
$primary_address = '';
|
||||
$x = zot_get_hublocs($rr['channel_hash']);
|
||||
$x = Libzot::get_hublocs($rr['channel_hash']);
|
||||
|
||||
if($x) {
|
||||
foreach($x as $xx) {
|
||||
if($xx['hubloc_url'] === z_root() && $xx['hubloc_sitekey'] === $sitekey) {
|
||||
@@ -42,13 +46,12 @@ class Fhublocs extends \Zotlabs\Web\Controller {
|
||||
if($y)
|
||||
$primary_address = $y[0]['xchan_addr'];
|
||||
|
||||
$hub_address = channel_reddress($rr['channel']);
|
||||
|
||||
|
||||
$hub_address = channel_reddress($rr);
|
||||
|
||||
$primary = (($hub_address === $primary_address) ? 1 : 0);
|
||||
if(! $y)
|
||||
$primary = 1;
|
||||
|
||||
|
||||
$m = q("delete from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' ",
|
||||
dbesc($rr['channel_hash']),
|
||||
dbesc(z_root())
|
||||
@@ -56,7 +59,7 @@ class Fhublocs extends \Zotlabs\Web\Controller {
|
||||
|
||||
// Create a verified hub location pointing to this site.
|
||||
|
||||
|
||||
/*
|
||||
$h = hubloc_store_lowlevel(
|
||||
[
|
||||
'hubloc_guid' => $rr['channel_guid'],
|
||||
@@ -72,7 +75,26 @@ class Fhublocs extends \Zotlabs\Web\Controller {
|
||||
'hubloc_sitekey' => $sitekey
|
||||
]
|
||||
);
|
||||
|
||||
*/
|
||||
$h = hubloc_store_lowlevel(
|
||||
[
|
||||
'hubloc_guid' => $rr['channel_guid'],
|
||||
'hubloc_guid_sig' => $rr['channel_guid_sig'],
|
||||
'hubloc_hash' => $rr['channel_hash'],
|
||||
'hubloc_id_url' => channel_url($rr),
|
||||
'hubloc_addr' => channel_reddress($rr),
|
||||
'hubloc_primary' => intval($primary),
|
||||
'hubloc_url' => z_root(),
|
||||
'hubloc_url_sig' => Libzot::sign(z_root(), $rr['channel_prvkey']),
|
||||
'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), $sitekey),
|
||||
'hubloc_host' => \App::get_hostname(),
|
||||
'hubloc_callback' => z_root() . '/zot',
|
||||
'hubloc_sitekey' => $sitekey,
|
||||
'hubloc_network' => 'zot6',
|
||||
'hubloc_updated' => datetime_convert()
|
||||
]
|
||||
);
|
||||
|
||||
if($h)
|
||||
$o . 'local hubloc created for ' . $rr['channel_name'] . EOL;
|
||||
else
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
require_once('include/attach.php');
|
||||
require_once('include/channel.php');
|
||||
require_once('include/photos.php');
|
||||
@@ -41,7 +43,7 @@ class File_upload extends \Zotlabs\Web\Controller {
|
||||
|
||||
$sync = attach_export_data($channel,$hash);
|
||||
if($sync) {
|
||||
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
}
|
||||
goaway(z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']);
|
||||
|
||||
@@ -97,7 +99,7 @@ class File_upload extends \Zotlabs\Web\Controller {
|
||||
if($r['success']) {
|
||||
$sync = attach_export_data($channel,$r['data']['hash']);
|
||||
if($sync)
|
||||
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ class Filer extends \Zotlabs\Web\Controller {
|
||||
intval(local_channel())
|
||||
);
|
||||
if($r) {
|
||||
$x = q("update item set item_retained = 1 where id = %d and uid = %d",
|
||||
$x = q("update item set item_retained = 1, changed = '%s' where id = %d and uid = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($r[0]['parent']),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
@@ -28,10 +28,14 @@ class Filerm extends \Zotlabs\Web\Controller {
|
||||
intval($item_id),
|
||||
dbesc($term)
|
||||
);
|
||||
|
||||
$x = q("update item set item_retained = 0, changed = '%s' where id = %d and uid = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($item_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if(x($_SESSION,'return_url'))
|
||||
goaway(z_root() . '/' . $_SESSION['return_url']);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Zotlabs\Module;
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
class Filestorage extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -35,12 +35,12 @@ class Filestorage extends \Zotlabs\Web\Controller {
|
||||
|
||||
$url = get_cloud_url($channel_id, $channel['channel_address'], $resource);
|
||||
|
||||
//get the object before permissions change so we can catch eventual former allowed members
|
||||
$object = get_file_activity_object($channel_id, $resource, $url);
|
||||
|
||||
attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true);
|
||||
|
||||
file_activity($channel_id, $object, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], 'post', $notify);
|
||||
if($notify) {
|
||||
$observer = \App::get_observer();
|
||||
attach_store_item($channel, $observer, $resource);
|
||||
}
|
||||
|
||||
goaway(dirname($url));
|
||||
}
|
||||
@@ -131,7 +131,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
|
||||
if(! $admin_delete) {
|
||||
$sync = attach_export_data($channel, $f['hash'], true);
|
||||
if($sync) {
|
||||
build_sync_packet($channel['channel_id'], array('file' => array($sync)));
|
||||
Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,88 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\LDSignatures;
|
||||
use Zotlabs\Lib\Connect;
|
||||
use Zotlabs\Daemon\Master;
|
||||
|
||||
require_once('include/follow.php');
|
||||
|
||||
|
||||
class Follow extends \Zotlabs\Web\Controller {
|
||||
class Follow extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
if(! local_channel()) {
|
||||
if (ActivityStreams::is_as_request() && argc() == 2) {
|
||||
|
||||
$abook_id = intval(argv(1));
|
||||
if(! $abook_id)
|
||||
return;
|
||||
|
||||
$r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d",
|
||||
intval($abook_id)
|
||||
);
|
||||
if (! $r) {
|
||||
return;
|
||||
}
|
||||
|
||||
$chan = channelx_by_n($r[0]['abook_channel']);
|
||||
|
||||
if (! $chan) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
$actor = Activity::encode_person($chan,true,true);
|
||||
if (! $actor) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
$x = array_merge(['@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1',
|
||||
z_root() . ZOT_APSCHEMA_REV
|
||||
]],
|
||||
[
|
||||
'id' => z_root() . '/follow/' . $r[0]['abook_id'],
|
||||
'type' => 'Follow',
|
||||
'actor' => $actor,
|
||||
'object' => $r[0]['xchan_url']
|
||||
]);
|
||||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
|
||||
$x['signature'] = LDSignatures::sign($x,$chan);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $ret;
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
if (! local_channel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$uid = local_channel();
|
||||
$url = notags(trim(punify($_REQUEST['url'])));
|
||||
$return_url = $_SESSION['return_url'];
|
||||
$confirm = intval($_REQUEST['confirm']);
|
||||
$interactive = (($_REQUEST['interactive']) ? intval($_REQUEST['interactive']) : 1);
|
||||
$channel = \App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
|
||||
$result = new_contact($uid,$url,$channel,$interactive,$confirm);
|
||||
$result = Connect::connect($channel,$url);
|
||||
|
||||
if($result['success'] == false) {
|
||||
if($result['message'])
|
||||
if ($result['success'] == false) {
|
||||
if ($result['message']) {
|
||||
notice($result['message']);
|
||||
if($interactive) {
|
||||
}
|
||||
if ($interactive) {
|
||||
goaway($return_url);
|
||||
}
|
||||
else {
|
||||
@@ -36,8 +93,8 @@ class Follow extends \Zotlabs\Web\Controller {
|
||||
info( t('Connection added.') . EOL);
|
||||
|
||||
$clone = array();
|
||||
foreach($result['abook'] as $k => $v) {
|
||||
if(strpos($k,'abook_') === 0) {
|
||||
foreach ($result['abook'] as $k => $v) {
|
||||
if (strpos($k,'abook_') === 0) {
|
||||
$clone[$k] = $v;
|
||||
}
|
||||
}
|
||||
@@ -46,20 +103,21 @@ class Follow extends \Zotlabs\Web\Controller {
|
||||
unset($clone['abook_channel']);
|
||||
|
||||
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
|
||||
if($abconfig)
|
||||
if ($abconfig) {
|
||||
$clone['abconfig'] = $abconfig;
|
||||
}
|
||||
Libsync::build_sync_packet(0, [ 'abook' => [ $clone ] ], true);
|
||||
|
||||
build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)), true);
|
||||
|
||||
$can_view_stream = intval(get_abconfig($channel['channel_id'],$clone['abook_xchan'],'their_perms','view_stream'));
|
||||
$can_view_stream = their_perms_contains($channel['channel_id'],$clone['abook_xchan'],'view_stream');
|
||||
|
||||
// If we can view their stream, pull in some posts
|
||||
|
||||
if(($can_view_stream) || ($result['abook']['xchan_network'] === 'rss'))
|
||||
\Zotlabs\Daemon\Master::Summon(array('Onepoll',$result['abook']['abook_id']));
|
||||
if (($can_view_stream) || ($result['abook']['xchan_network'] === 'rss')) {
|
||||
Master::Summon([ 'Onepoll', $result['abook']['abook_id'] ]);
|
||||
}
|
||||
|
||||
if($interactive) {
|
||||
goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1');
|
||||
if ($interactive) {
|
||||
goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?follow=1');
|
||||
}
|
||||
else {
|
||||
json_return_and_die([ 'success' => true ]);
|
||||
@@ -68,7 +126,7 @@ class Follow extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
function get() {
|
||||
if(! local_channel()) {
|
||||
if (! local_channel()) {
|
||||
return login();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
/**
|
||||
* module: getfile
|
||||
*
|
||||
@@ -35,7 +38,6 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
$sig = $_POST['signature'];
|
||||
$resource = $_POST['resource'];
|
||||
$revision = intval($_POST['revision']);
|
||||
$resolution = (-1);
|
||||
|
||||
if(! $hash)
|
||||
killme();
|
||||
@@ -47,18 +49,18 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
if($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
|
||||
if($keyId) {
|
||||
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
|
||||
where hubloc_addr = '%s' limit 1",
|
||||
where hubloc_addr = '%s'",
|
||||
dbesc(str_replace('acct:','',$keyId))
|
||||
);
|
||||
if($r) {
|
||||
$hubloc = $r[0];
|
||||
$verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']);
|
||||
$hubloc = Libzot::zot_record_preferred($r);
|
||||
$verified = HTTPSig::verify('',$hubloc['xchan_pubkey']);
|
||||
if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) {
|
||||
$header_verified = true;
|
||||
}
|
||||
@@ -81,9 +83,14 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
killme();
|
||||
}
|
||||
|
||||
if(substr($resource,-2,1) == '-') {
|
||||
if(isset($_POST['resolution']))
|
||||
$resolution = intval($_POST['resolution']);
|
||||
elseif(substr($resource,-2,1) == '-') {
|
||||
$resolution = intval(substr($resource,-1,1));
|
||||
$resource = substr($resource,0,-2);
|
||||
}
|
||||
else {
|
||||
$resolution = (-1);
|
||||
}
|
||||
|
||||
$slop = intval(get_pconfig($channel['channel_id'],'system','getfile_time_slop'));
|
||||
@@ -106,9 +113,10 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($resolution > 0) {
|
||||
$r = q("select * from photo where resource_id = '%s' and uid = %d limit 1",
|
||||
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1",
|
||||
dbesc($resource),
|
||||
intval($channel['channel_id'])
|
||||
intval($channel['channel_id']),
|
||||
$resolution
|
||||
);
|
||||
if($r) {
|
||||
header('Content-type: ' . $r[0]['mimetype']);
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Zotlabs\Module;
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
require_once('include/group.php');
|
||||
|
||||
@@ -80,7 +81,7 @@ class Group extends Controller {
|
||||
info( t('Privacy group updated.') . EOL );
|
||||
|
||||
|
||||
build_sync_packet(local_channel(),null,true);
|
||||
Libsync::build_sync_packet(local_channel(),null,true);
|
||||
}
|
||||
|
||||
goaway(z_root() . '/group/' . argv(1) . '/' . argv(2));
|
||||
@@ -177,7 +178,7 @@ class Group extends Controller {
|
||||
if($r)
|
||||
$result = group_rmv(local_channel(),$r[0]['gname']);
|
||||
if($result) {
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$argv(2) ];
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group' => argv(2) ];
|
||||
call_hooks ('privacygroup_extras_drop',$hookinfo);
|
||||
info( t('Privacy group removed.') . EOL);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,10 @@ class Help extends \Zotlabs\Web\Controller {
|
||||
case IMAGETYPE_PNG:
|
||||
header("Content-Type: image/png");
|
||||
break;
|
||||
default:
|
||||
case IMAGETYPE_WEBP:
|
||||
header("Content-Type: image/webp");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
header("Content-Length: " . filesize($realpath));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user