mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 09:01:15 -04:00
Compare commits
2383 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8ac25c35a | ||
|
|
2dd47a9f59 | ||
|
|
a92ad512bb | ||
|
|
e39b29cc4b | ||
|
|
76ed9f3915 | ||
|
|
fd6ec17d4b | ||
|
|
8de364c83e | ||
|
|
9b9ac5054f | ||
|
|
9efea4e188 | ||
|
|
d45df824ed | ||
|
|
50ead82bc4 | ||
|
|
c43f501716 | ||
|
|
86d471834e | ||
|
|
a1f7f7a966 | ||
|
|
081d82218b | ||
|
|
cca3eb8c56 | ||
|
|
933c097a52 | ||
|
|
f5912e05ef | ||
|
|
e94eb1af0c | ||
|
|
0ab7996a2a | ||
|
|
faeec0b77b | ||
|
|
ebc84eab3f | ||
|
|
b560b6fbd3 | ||
|
|
c6b3bc5b20 | ||
|
|
e31cb28b08 | ||
|
|
458fa7bfeb | ||
|
|
fab3f0f2de | ||
|
|
c8d9238c58 | ||
|
|
5aa79caf84 | ||
|
|
12cabbde9e | ||
|
|
ca3ab2014f | ||
|
|
3e6283a262 | ||
|
|
bc0d0a6b39 | ||
|
|
6a4727e3eb | ||
|
|
ff6d1c808d | ||
|
|
197d15b7de | ||
|
|
bb5f6a1d79 | ||
|
|
e8c6121b4e | ||
|
|
bed81d785c | ||
|
|
0503914527 | ||
|
|
cb65ae6848 | ||
|
|
652d083766 | ||
|
|
091d9c10fb | ||
|
|
835fe10bfe | ||
|
|
5a474f94e0 | ||
|
|
d322feeb54 | ||
|
|
842c7b31fb | ||
|
|
1034f02d4d | ||
|
|
3f6b6dfaf3 | ||
|
|
d3d4dee36a | ||
|
|
7002248325 | ||
|
|
d8d0f01f80 | ||
|
|
b3b842c071 | ||
|
|
aca8d1b8f9 | ||
|
|
4f328740dc | ||
|
|
2f1c2f42b1 | ||
|
|
d42a998e49 | ||
|
|
167db22e15 | ||
|
|
108777251e | ||
|
|
088713a555 | ||
|
|
7582ebc9c8 | ||
|
|
97d9764f01 | ||
|
|
dfcd8395d5 | ||
|
|
6e91bee0ba | ||
|
|
cf791a1909 | ||
|
|
c6d872d177 | ||
|
|
cc4f3a827c | ||
|
|
0489fbb685 | ||
|
|
7da23603ec | ||
|
|
afb4ae2109 | ||
|
|
e024375b15 | ||
|
|
3632fb359f | ||
|
|
2a3ba5d5f0 | ||
|
|
5b9dc764c5 | ||
|
|
24a0d4f308 | ||
|
|
88f5b10b22 | ||
|
|
cf69859885 | ||
|
|
af71f7f8cd | ||
|
|
ec22ca7553 | ||
|
|
c42d8a81c7 | ||
|
|
0e7473c3ba | ||
|
|
f4f9ccc3b2 | ||
|
|
a84cec4acd | ||
|
|
cf6b7a4236 | ||
|
|
998f46b45c | ||
|
|
5ca352a6c3 | ||
|
|
a34bd3b013 | ||
|
|
c268bc327a | ||
|
|
e79a27c654 | ||
|
|
2f0bac8ddf | ||
|
|
12d7d1c3f0 | ||
|
|
34ca2cddd4 | ||
|
|
fa076efd3b | ||
|
|
b55676d089 | ||
|
|
9b71c090c5 | ||
|
|
0f8e4e4eed | ||
|
|
de1e3d7b17 | ||
|
|
3d077a0bc6 | ||
|
|
c74d1f4bf7 | ||
|
|
776e1211bc | ||
|
|
b5a8ca6ef7 | ||
|
|
2c198ed89a | ||
|
|
17fdeb9e1f | ||
|
|
e41858f57c | ||
|
|
12089e127a | ||
|
|
c75b8711b1 | ||
|
|
67322c1264 | ||
|
|
607f0346f4 | ||
|
|
d5bb34f65d | ||
|
|
3e18efd89f | ||
|
|
bec3cb48e5 | ||
|
|
e8d2819c42 | ||
|
|
cc85c2f4d7 | ||
|
|
bee4fa9937 | ||
|
|
14ab5801d2 | ||
|
|
fd8a5ff4c4 | ||
|
|
ef9ae0db94 | ||
|
|
4db384da34 | ||
|
|
0784d2ea4e | ||
|
|
b90db6931d | ||
|
|
25497336bb | ||
|
|
a0ee9557f0 | ||
|
|
7b3eb09067 | ||
|
|
1fc3be0c9f | ||
|
|
6de327402b | ||
|
|
131ce826c3 | ||
|
|
a3f4ad9ea0 | ||
|
|
ec3b1131d9 | ||
|
|
74c0345009 | ||
|
|
628b03da29 | ||
|
|
bd59fb0b4e | ||
|
|
443b436be8 | ||
|
|
993d648011 | ||
|
|
343f3059e6 | ||
|
|
10f8fe8973 | ||
|
|
e44bf42c64 | ||
|
|
3d1684fa94 | ||
|
|
d882bad706 | ||
|
|
e5c8273f72 | ||
|
|
440f7bacd6 | ||
|
|
ba22d3e9b6 | ||
|
|
33463152e8 | ||
|
|
657af3024e | ||
|
|
7d82a34538 | ||
|
|
a0b788e96a | ||
|
|
50c14d353b | ||
|
|
b63aa3079b | ||
|
|
25be24e6b8 | ||
|
|
2ec2da5dff | ||
|
|
b3df15a3c6 | ||
|
|
2171686284 | ||
|
|
b382edc61d | ||
|
|
5ae21d04b0 | ||
|
|
b0825ead84 | ||
|
|
2980f852aa | ||
|
|
5e07ebe7fa | ||
|
|
baabb3a873 | ||
|
|
5ee1c3f2c8 | ||
|
|
3fe2a2b181 | ||
|
|
3d2b923102 | ||
|
|
43c941d370 | ||
|
|
e1721b8496 | ||
|
|
ccf3ed185f | ||
|
|
99af27770e | ||
|
|
e9088bd52e | ||
|
|
f72b8ce30f | ||
|
|
19bb96121b | ||
|
|
69ef7cf168 | ||
|
|
f1aace5a22 | ||
|
|
0718ac514d | ||
|
|
d289994da4 | ||
|
|
30f258b3f9 | ||
|
|
d06d22c7c9 | ||
|
|
57c301d59c | ||
|
|
4bde2f64bd | ||
|
|
8ca487115f | ||
|
|
7ad0a1e557 | ||
|
|
1aa626f0e8 | ||
|
|
7e36d17135 | ||
|
|
2f7e875eb4 | ||
|
|
3ab8632d3b | ||
|
|
190fc4e3c4 | ||
|
|
3eb1b9d168 | ||
|
|
2fb3d6ddf5 | ||
|
|
bf74a75303 | ||
|
|
7d1b240954 | ||
|
|
2db3e4ca48 | ||
|
|
cee2e63278 | ||
|
|
9d5732400f | ||
|
|
3cb0613d04 | ||
|
|
d9920fce3a | ||
|
|
2765a0a9fd | ||
|
|
92ea7fcfb1 | ||
|
|
9d96793e1a | ||
|
|
7776283a47 | ||
|
|
c9d4802bf1 | ||
|
|
37558e24f8 | ||
|
|
67cf9f6caf | ||
|
|
16146af039 | ||
|
|
6a7e06f11c | ||
|
|
adba56a5e5 | ||
|
|
90c9fc5338 | ||
|
|
0a09f507fc | ||
|
|
9ea60ba79f | ||
|
|
43ef82aaaa | ||
|
|
7171d790f4 | ||
|
|
4099549609 | ||
|
|
4e4bffe5c5 | ||
|
|
1c8000d026 | ||
|
|
ff34a787c3 | ||
|
|
84c5f57d22 | ||
|
|
64181c7cf1 | ||
|
|
3c5f840cf0 | ||
|
|
1fa4bc9ac0 | ||
|
|
b742910107 | ||
|
|
b7f124072f | ||
|
|
ec02eda113 | ||
|
|
8d8523684c | ||
|
|
8a0c7b3fe1 | ||
|
|
a29dbaba21 | ||
|
|
51ad4fac01 | ||
|
|
d863ba1b2a | ||
|
|
175001eccd | ||
|
|
846d99cfce | ||
|
|
2486a9c914 | ||
|
|
a47a81db6f | ||
|
|
587e790892 | ||
|
|
f73a83aa55 | ||
|
|
513cf2b8e2 | ||
|
|
ea215697ed | ||
|
|
d40686e5d0 | ||
|
|
0b7d343c7c | ||
|
|
d692ed634a | ||
|
|
7d4e07df79 | ||
|
|
8211bc09d4 | ||
|
|
5705005ca3 | ||
|
|
79b4642b32 | ||
|
|
c9981ff0e1 | ||
|
|
0948b061fe | ||
|
|
a537e78f14 | ||
|
|
25edeebf2b | ||
|
|
a7a4727591 | ||
|
|
bc2afb21e1 | ||
|
|
64fe93b9eb | ||
|
|
33d2a852c9 | ||
|
|
300679c053 | ||
|
|
f9c85c52f3 | ||
|
|
98985b2761 | ||
|
|
8fe00d428d | ||
|
|
02229482b8 | ||
|
|
9a5c1aa02f | ||
|
|
a46e340a13 | ||
|
|
70c3cd99ac | ||
|
|
e89bbde575 | ||
|
|
2ee1e2af72 | ||
|
|
c3ad21c548 | ||
|
|
635a24dff4 | ||
|
|
a03423794a | ||
|
|
d4e723a8eb | ||
|
|
ded9f18b8a | ||
|
|
3a2e5d480c | ||
|
|
26e851ff7f | ||
|
|
89ec043ce1 | ||
|
|
98f0272a84 | ||
|
|
0933925a2b | ||
|
|
e92929fce4 | ||
|
|
f388412c48 | ||
|
|
836de7f1a5 | ||
|
|
43008aa42b | ||
|
|
7618d8301a | ||
|
|
09cfc979e4 | ||
|
|
00fc5541db | ||
|
|
954d06bdb7 | ||
|
|
12828ee4d4 | ||
|
|
c2e007a839 | ||
|
|
605bf3b9d3 | ||
|
|
ebd0333256 | ||
|
|
d7dcf192c7 | ||
|
|
2ad6f6e11f | ||
|
|
36a814b03e | ||
|
|
92bc99a805 | ||
|
|
b5ce207344 | ||
|
|
d04ff264fa | ||
|
|
9ad2b017e2 | ||
|
|
1fd5f5c893 | ||
|
|
43260891b7 | ||
|
|
aef0350346 | ||
|
|
83fbb0678c | ||
|
|
df3778c64f | ||
|
|
0dc09ea238 | ||
|
|
f085c3c98f | ||
|
|
8d4b1ba7d4 | ||
|
|
b3c543265d | ||
|
|
6eee404bb1 | ||
|
|
ec4226b5de | ||
|
|
8266a1490a | ||
|
|
56554710ea | ||
|
|
6a101e6260 | ||
|
|
f12038e63e | ||
|
|
ad2bf187bb | ||
|
|
4cbd97e409 | ||
|
|
e67c780afd | ||
|
|
0cbdeb7bf1 | ||
|
|
6be464ef84 | ||
|
|
54845a7627 | ||
|
|
2f6da0be7e | ||
|
|
cf87a5af3b | ||
|
|
207057c92d | ||
|
|
5300f180db | ||
|
|
ec7166eb00 | ||
|
|
36f041a1ff | ||
|
|
0dd2e9004d | ||
|
|
94f1c001f1 | ||
|
|
531a03562d | ||
|
|
3699f78e95 | ||
|
|
ebd2283b38 | ||
|
|
a7788570e5 | ||
|
|
2932ac9d86 | ||
|
|
888c211f44 | ||
|
|
61cf92ebdd | ||
|
|
80ec45e4f9 | ||
|
|
9e9851681f | ||
|
|
8394d4857c | ||
|
|
c700a017a0 | ||
|
|
c19eb94c52 | ||
|
|
597f24ca49 | ||
|
|
eb793b1601 | ||
|
|
07525c5b45 | ||
|
|
35df50c39d | ||
|
|
406ca20634 | ||
|
|
021e7861b8 | ||
|
|
5dfe4ef6f8 | ||
|
|
60a0fdc76b | ||
|
|
cd760454a5 | ||
|
|
c7144dbf96 | ||
|
|
c31e203104 | ||
|
|
6feefc5ce0 | ||
|
|
1d7f9e05ed | ||
|
|
6a858b29fd | ||
|
|
3f0e687558 | ||
|
|
ba412bc6cf | ||
|
|
31abcac4b4 | ||
|
|
d7f04ff6ee | ||
|
|
76fd81fad1 | ||
|
|
1cfcffc510 | ||
|
|
eaf9003ca2 | ||
|
|
751d6fe8a4 | ||
|
|
20ca6676d2 | ||
|
|
eded0f6c09 | ||
|
|
b5049651ad | ||
|
|
c95a6fe1e5 | ||
|
|
cd97c32444 | ||
|
|
70b204cb3f | ||
|
|
d2f1edfad8 | ||
|
|
2ddfcd5222 | ||
|
|
787ee411ce | ||
|
|
200d3577fa | ||
|
|
8ab99747f5 | ||
|
|
88f7c2041d | ||
|
|
43cb21329f | ||
|
|
b8a5f5fbf2 | ||
|
|
7ccd7b439f | ||
|
|
f0eceb03ed | ||
|
|
c2b9fc1a49 | ||
|
|
4d3a555b53 | ||
|
|
e35ab97b7e | ||
|
|
f9793e870f | ||
|
|
e48fedd526 | ||
|
|
b899ed3d64 | ||
|
|
e4adb881cb | ||
|
|
aa2450fae1 | ||
|
|
d9245566f5 | ||
|
|
16cc695115 | ||
|
|
f0e5ce7fd1 | ||
|
|
ea721d380b | ||
|
|
e193b6d870 | ||
|
|
766fc92a3b | ||
|
|
df6f2abfbe | ||
|
|
684245f24d | ||
|
|
01b081d809 | ||
|
|
a34d8852b6 | ||
|
|
18b6d48944 | ||
|
|
f3fa09fc91 | ||
|
|
cb2d8b4ba6 | ||
|
|
a9da370c0b | ||
|
|
b5620cb794 | ||
|
|
cf62e07bec | ||
|
|
ec4526b5f4 | ||
|
|
806f50eee3 | ||
|
|
6956eadaad | ||
|
|
9542c1d63c | ||
|
|
81bb02afb7 | ||
|
|
b8abf806ca | ||
|
|
0d10f5ba65 | ||
|
|
89409d0577 | ||
|
|
144283ca1c | ||
|
|
c56e2953cf | ||
|
|
e1d40348ce | ||
|
|
4def370980 | ||
|
|
54df52675b | ||
|
|
12ebdf27c0 | ||
|
|
de0f7ea5d4 | ||
|
|
72151bc123 | ||
|
|
8889abd5a4 | ||
|
|
7f7dcd2f33 | ||
|
|
95c3b1696e | ||
|
|
87cd1f87f4 | ||
|
|
21c4976a3a | ||
|
|
ec91e51142 | ||
|
|
f1c798e9ac | ||
|
|
f6996f4999 | ||
|
|
9ac5504377 | ||
|
|
91f3c722d6 | ||
|
|
31cf2c688c | ||
|
|
81d3ba5151 | ||
|
|
19daadbfd7 | ||
|
|
0acb371f62 | ||
|
|
18d990a034 | ||
|
|
85b6e352d4 | ||
|
|
c389aee112 | ||
|
|
725e57a27a | ||
|
|
9aab47de07 | ||
|
|
e6a6723d1f | ||
|
|
6e7c7771bd | ||
|
|
c609fc71bd | ||
|
|
b50f1657c3 | ||
|
|
bc1cc65ff2 | ||
|
|
697e59f9a4 | ||
|
|
61d6239c68 | ||
|
|
eba69f85c7 | ||
|
|
19b96e37fb | ||
|
|
14186f5c18 | ||
|
|
44593a3c8d | ||
|
|
4964a32c55 | ||
|
|
3d4ad94dcc | ||
|
|
6d5f98072d | ||
|
|
1a15c775f8 | ||
|
|
2d716b74b9 | ||
|
|
cc9fd4f4a4 | ||
|
|
43c5b72317 | ||
|
|
2856ea6370 | ||
|
|
67d65d878d | ||
|
|
e19bb63857 | ||
|
|
dbc5e54a92 | ||
|
|
b8913335b1 | ||
|
|
872ac8846e | ||
|
|
8c16171855 | ||
|
|
2e47ef38a9 | ||
|
|
81b4d919e5 | ||
|
|
f6d88f20f3 | ||
|
|
598c3aa336 | ||
|
|
ccefb99cbe | ||
|
|
35ce7dbeab | ||
|
|
74610aca6f | ||
|
|
02d4c5ac90 | ||
|
|
7f35dda5cc | ||
|
|
13355d42f7 | ||
|
|
77e82d7475 | ||
|
|
da2df4eb55 | ||
|
|
62fbdf3f63 | ||
|
|
554745a25a | ||
|
|
e12c0ca3dc | ||
|
|
a18e297a26 | ||
|
|
2d82e1bd6b | ||
|
|
7476d8dccc | ||
|
|
04b96e2cdc | ||
|
|
7375824ed4 | ||
|
|
06d47deef8 | ||
|
|
85d000e792 | ||
|
|
3ac27d8004 | ||
|
|
854a6e3787 | ||
|
|
a36dd5a8b9 | ||
|
|
7c620cbe24 | ||
|
|
7472b96c95 | ||
|
|
3ba42d3dcf | ||
|
|
eb3a40b07a | ||
|
|
f0cce1c902 | ||
|
|
9f26b7aa9c | ||
|
|
febf766be0 | ||
|
|
35d9fd4860 | ||
|
|
4581abb6d1 | ||
|
|
8d3c5114ba | ||
|
|
80b6954c29 | ||
|
|
da37548e2e | ||
|
|
c658bbca24 | ||
|
|
3b9a9db664 | ||
|
|
4e921cfdcf | ||
|
|
bd24224b76 | ||
|
|
a5ac388889 | ||
|
|
4be123dc84 | ||
|
|
0ebb1f685f | ||
|
|
805a25eb62 | ||
|
|
4ca12afc9d | ||
|
|
6cfa2572a8 | ||
|
|
04ec986bf7 | ||
|
|
ee453c4acc | ||
|
|
4d3524ba9d | ||
|
|
29beea28c2 | ||
|
|
e2a289d614 | ||
|
|
59d3483a06 | ||
|
|
a99161abdf | ||
|
|
79d48dc92b | ||
|
|
becb898a51 | ||
|
|
268464ccde | ||
|
|
57aa96c412 | ||
|
|
cb74de7472 | ||
|
|
d35849c418 | ||
|
|
a9a112e063 | ||
|
|
1e87fe6b49 | ||
|
|
ed64eba13a | ||
|
|
0fbd0ca416 | ||
|
|
0a31267b1b | ||
|
|
97c7b010ed | ||
|
|
b6d30f6734 | ||
|
|
b9e1c38773 | ||
|
|
22d769ecae | ||
|
|
45ecd1b127 | ||
|
|
3f053611bd | ||
|
|
1582b8bc96 | ||
|
|
432e7e9714 | ||
|
|
31e237729c | ||
|
|
d2b03f6a9b | ||
|
|
51fe5ec982 | ||
|
|
ce9b01ce84 | ||
|
|
024b489af9 | ||
|
|
f980c2e3de | ||
|
|
db0e1c9f31 | ||
|
|
260c518562 | ||
|
|
689603de82 | ||
|
|
b51049227f | ||
|
|
0a86efc631 | ||
|
|
f8467845d2 | ||
|
|
9098bb431c | ||
|
|
86ed4f4f99 | ||
|
|
7795224e70 | ||
|
|
b729cee9e4 | ||
|
|
15bc5c64f3 | ||
|
|
440a132c6b | ||
|
|
f8447521a8 | ||
|
|
c8050ea865 | ||
|
|
11d831e4d7 | ||
|
|
15faf01ec9 | ||
|
|
82192d1ead | ||
|
|
7ee495624e | ||
|
|
64bbbc8053 | ||
|
|
4d3d868d19 | ||
|
|
45cc2d7bd8 | ||
|
|
15b45af550 | ||
|
|
91ebfbc215 | ||
|
|
011342ac1b | ||
|
|
5577383a48 | ||
|
|
dc336010db | ||
|
|
88fbeaddb0 | ||
|
|
7612d8246e | ||
|
|
53bb16e799 | ||
|
|
ed04104250 | ||
|
|
ee40cb337a | ||
|
|
bdae290ec4 | ||
|
|
53c3d0d53d | ||
|
|
ed981ec8e8 | ||
|
|
723d757091 | ||
|
|
92ada6eb98 | ||
|
|
975d8ef0c7 | ||
|
|
65e9ff357b | ||
|
|
66495e6838 | ||
|
|
efe65e1ba8 | ||
|
|
6b500ee3e1 | ||
|
|
1ad6308f97 | ||
|
|
5d82bf946e | ||
|
|
c8fe56e57d | ||
|
|
88b6353465 | ||
|
|
4afddabe15 | ||
|
|
360ae9080e | ||
|
|
956aec1448 | ||
|
|
4bcd093bef | ||
|
|
f62b294a72 | ||
|
|
c2adf1dcd1 | ||
|
|
0932d2a0a6 | ||
|
|
e451284256 | ||
|
|
49f12695cf | ||
|
|
8d26961639 | ||
|
|
c9ec5043b9 | ||
|
|
03bfb8a46f | ||
|
|
0c5a7ab19b | ||
|
|
1561e4a89c | ||
|
|
b09cbb72fb | ||
|
|
d57f4a9527 | ||
|
|
0e015d52a5 | ||
|
|
7e0416ac97 | ||
|
|
98112497ba | ||
|
|
f952d65cfd | ||
|
|
182dec3e57 | ||
|
|
8ab6076566 | ||
|
|
6506cab55b | ||
|
|
97e483d684 | ||
|
|
fe638c88e0 | ||
|
|
951e9c8c4f | ||
|
|
89415e1731 | ||
|
|
f9ab020d1d | ||
|
|
1828ef6b68 | ||
|
|
4903d7b1e9 | ||
|
|
c67fdd9480 | ||
|
|
9b5979c83a | ||
|
|
7460b1eecb | ||
|
|
7d03ff2043 | ||
|
|
1da494a2a5 | ||
|
|
00ccafc90d | ||
|
|
b767e7ddec | ||
|
|
31da1362de | ||
|
|
e0c619519f | ||
|
|
f1f1e56f87 | ||
|
|
33e4b6db72 | ||
|
|
1eae7b92d1 | ||
|
|
5b7a10401f | ||
|
|
1b8c5b9727 | ||
|
|
548936c6ca | ||
|
|
7beb500fb4 | ||
|
|
9c110e7b9b | ||
|
|
129f8107d3 | ||
|
|
cb01996039 | ||
|
|
33b738d00b | ||
|
|
cf7f380568 | ||
|
|
7e36727ce6 | ||
|
|
c2dc3e8dec | ||
|
|
7d1599f9b0 | ||
|
|
3d264f5a55 | ||
|
|
9389abdb75 | ||
|
|
f8f15f526f | ||
|
|
48bae9d421 | ||
|
|
c29261487c | ||
|
|
c3229643d0 | ||
|
|
2b03e51bfc | ||
|
|
4cc72db463 | ||
|
|
d434490bdf | ||
|
|
2c15efbf48 | ||
|
|
c26dede97f | ||
|
|
1d899d387e | ||
|
|
ea3390d626 | ||
|
|
a04ded9cca | ||
|
|
55b4eb7b22 | ||
|
|
fbb1d6aa41 | ||
|
|
5440a65607 | ||
|
|
36c9f9abff | ||
|
|
8295ccdda7 | ||
|
|
65892ba555 | ||
|
|
78938df133 | ||
|
|
ac6dec91f1 | ||
|
|
373612a046 | ||
|
|
c1afa306c9 | ||
|
|
65a20a780d | ||
|
|
b29e121113 | ||
|
|
f45ebfa223 | ||
|
|
a033c439f3 | ||
|
|
66e4bc327f | ||
|
|
df362e4f81 | ||
|
|
82ee980172 | ||
|
|
463a8d338e | ||
|
|
d074bb65da | ||
|
|
b7c411470b | ||
|
|
e09e6c5524 | ||
|
|
fa73c8d15e | ||
|
|
6060ca127b | ||
|
|
ca4e0351cf | ||
|
|
f3be2ecc9d | ||
|
|
135305d975 | ||
|
|
34aa8ba3cc | ||
|
|
28fe91dfa7 | ||
|
|
883b519714 | ||
|
|
9dae590c64 | ||
|
|
d4159e8333 | ||
|
|
90d04082a1 | ||
|
|
a84c7271f2 | ||
|
|
f46ddf2273 | ||
|
|
b401869d30 | ||
|
|
cc55716879 | ||
|
|
ddad4f604b | ||
|
|
dc553ab309 | ||
|
|
a2d170385b | ||
|
|
a275726988 | ||
|
|
863d4d83a1 | ||
|
|
d50381c9c6 | ||
|
|
c9bbe1a735 | ||
|
|
18b9d1efd8 | ||
|
|
85f1845d15 | ||
|
|
c34fc416a2 | ||
|
|
7794ee5a88 | ||
|
|
65068479b9 | ||
|
|
655ae9d1cd | ||
|
|
76163fc37b | ||
|
|
92f3c5ae21 | ||
|
|
c3ec5d4d6a | ||
|
|
0aeb4d6fb5 | ||
|
|
edd4ac791f | ||
|
|
27577824de | ||
|
|
281b2261af | ||
|
|
3eaf0b7f23 | ||
|
|
76ad2c0fa4 | ||
|
|
efaadf54d3 | ||
|
|
6f71c6d950 | ||
|
|
ad0b0364b8 | ||
|
|
e8c2e17bc9 | ||
|
|
6fae291cc8 | ||
|
|
1e48be7ab7 | ||
|
|
0cd4c34101 | ||
|
|
02401ea9fd | ||
|
|
18c8f1b903 | ||
|
|
4171a0136a | ||
|
|
ba29a6ce4d | ||
|
|
d72a096fa5 | ||
|
|
ed99392001 | ||
|
|
50e9a12ca5 | ||
|
|
d6b259bb27 | ||
|
|
f94b046333 | ||
|
|
5e8e6dc458 | ||
|
|
9751efb709 | ||
|
|
7b2f53cc69 | ||
|
|
22e0175ab7 | ||
|
|
0ffb09aa40 | ||
|
|
8054d7ad66 | ||
|
|
d3e70acacd | ||
|
|
6f520cadb7 | ||
|
|
becdd64257 | ||
|
|
464a0634d6 | ||
|
|
391db61629 | ||
|
|
e6450acc03 | ||
|
|
e75ae17662 | ||
|
|
3b3c93f9b3 | ||
|
|
b4693870ba | ||
|
|
5aee2f172e | ||
|
|
6b8b42fb21 | ||
|
|
320e95aaae | ||
|
|
1bcf84f275 | ||
|
|
a8e0bd1f12 | ||
|
|
eb05e5a205 | ||
|
|
d316d9436b | ||
|
|
b2e4a4b2b1 | ||
|
|
e1d622c49f | ||
|
|
8bb77bcfd6 | ||
|
|
f4ecc0dfb9 | ||
|
|
111ae9812c | ||
|
|
a9070382e7 | ||
|
|
9e22641425 | ||
|
|
19007dd8eb | ||
|
|
03e1f5f8a4 | ||
|
|
6bb73e14b6 | ||
|
|
41f84dabcc | ||
|
|
cd79d12e5b | ||
|
|
a6162d3134 | ||
|
|
ba73845bad | ||
|
|
7ece28b981 | ||
|
|
34b28cd8d3 | ||
|
|
9a170791e4 | ||
|
|
5799a073fe | ||
|
|
44b559fb1d | ||
|
|
2167d12b3f | ||
|
|
e312c381d8 | ||
|
|
af6f7f244e | ||
|
|
f3f49cf80f | ||
|
|
85b1bc7929 | ||
|
|
de36172af3 | ||
|
|
f5fba51f5c | ||
|
|
a2185c7886 | ||
|
|
08c9152abd | ||
|
|
70fa7ad8d0 | ||
|
|
cd081ac077 | ||
|
|
197338a727 | ||
|
|
61e7791d31 | ||
|
|
de91d2c804 | ||
|
|
11f5550512 | ||
|
|
d99611e7dd | ||
|
|
c0933c90e8 | ||
|
|
21b3ba38e7 | ||
|
|
bac87a8aec | ||
|
|
fae5515350 | ||
|
|
68d5969d33 | ||
|
|
a235917d48 | ||
|
|
d2eb10d7ff | ||
|
|
89bf71b227 | ||
|
|
3773bceb46 | ||
|
|
7686b48723 | ||
|
|
4ecb4189b8 | ||
|
|
840dbbe8ba | ||
|
|
ab4863a2e0 | ||
|
|
8c2442eca5 | ||
|
|
8b78e18fb8 | ||
|
|
66640a206e | ||
|
|
15c90371e0 | ||
|
|
00fe7bb1bb | ||
|
|
a2728167bc | ||
|
|
6326605c99 | ||
|
|
7cd4f60922 | ||
|
|
af719fea40 | ||
|
|
0af458768f | ||
|
|
3ba46873ba | ||
|
|
f4cc91f0f5 | ||
|
|
f813671b67 | ||
|
|
d0d6170a71 | ||
|
|
74f8f2d956 | ||
|
|
f0ee4c3cef | ||
|
|
6878445319 | ||
|
|
de34dac6cc | ||
|
|
1c8d298f3f | ||
|
|
777af6e7ad | ||
|
|
82dbdf7c70 | ||
|
|
4cf05891d7 | ||
|
|
d4198223bc | ||
|
|
1b4bbcc891 | ||
|
|
0e9d99c603 | ||
|
|
3ed444b4b4 | ||
|
|
cd98e75a42 | ||
|
|
77793e17c0 | ||
|
|
552796286e | ||
|
|
3f031399cb | ||
|
|
e486442eb1 | ||
|
|
2035828042 | ||
|
|
0a16674f6e | ||
|
|
4fbedb6750 | ||
|
|
9365b8691e | ||
|
|
6b0c61ac6b | ||
|
|
0a13c794ab | ||
|
|
a53f286467 | ||
|
|
e4ed5ed264 | ||
|
|
74441f2f00 | ||
|
|
007de17702 | ||
|
|
ecf2e4e0ee | ||
|
|
33825ba0b4 | ||
|
|
67db1c6e9b | ||
|
|
03910453a9 | ||
|
|
30962dadbf | ||
|
|
33951dc1e4 | ||
|
|
893847c649 | ||
|
|
fbbc53838c | ||
|
|
abdf6f40a2 | ||
|
|
7bc0340106 | ||
|
|
bfb9f10234 | ||
|
|
3f34c73f09 | ||
|
|
92f420f77c | ||
|
|
78716c42d6 | ||
|
|
e6aed4fb8e | ||
|
|
064effe5fd | ||
|
|
93ac3c985f | ||
|
|
523765b968 | ||
|
|
fe97b63e0b | ||
|
|
3836e75c89 | ||
|
|
28ae78c579 | ||
|
|
bdd6d878f1 | ||
|
|
8134e9cae0 | ||
|
|
70ee41f252 | ||
|
|
491dffd9b7 | ||
|
|
ad42890a0b | ||
|
|
5a971a3731 | ||
|
|
ab4455c54c | ||
|
|
6cca06f641 | ||
|
|
c5d37a0831 | ||
|
|
57645386b2 | ||
|
|
b242347fa1 | ||
|
|
15b2aa660b | ||
|
|
4da4f2367f | ||
|
|
9612a69a64 | ||
|
|
4e9d8e1a83 | ||
|
|
6083bfea2f | ||
|
|
08264f8d11 | ||
|
|
8b93136773 | ||
|
|
c7a82a6a84 | ||
|
|
ef67e18161 | ||
|
|
08d2fb4ed4 | ||
|
|
836637621d | ||
|
|
6e7a2d0d96 | ||
|
|
101005f3d2 | ||
|
|
8f88543478 | ||
|
|
f1ac5bb667 | ||
|
|
8e5df2dd22 | ||
|
|
441525750f | ||
|
|
9acfc44ac9 | ||
|
|
d5bd09b983 | ||
|
|
45350179b4 | ||
|
|
d0f3d2b2a5 | ||
|
|
3742fe80fc | ||
|
|
e191966e69 | ||
|
|
2c8e122008 | ||
|
|
2729f466d5 | ||
|
|
f4b71fbec1 | ||
|
|
6695225492 | ||
|
|
4f74d1d877 | ||
|
|
bee84e9b00 | ||
|
|
faaa2d4472 | ||
|
|
917c6caa14 | ||
|
|
cd59c67c67 | ||
|
|
37f1b774b7 | ||
|
|
828636847e | ||
|
|
06b5f71075 | ||
|
|
8d37a4239a | ||
|
|
a925b08e80 | ||
|
|
46aefd8883 | ||
|
|
38a48de826 | ||
|
|
254e30bea1 | ||
|
|
a16692eeb0 | ||
|
|
485a232ae6 | ||
|
|
d3f8118874 | ||
|
|
0d544e2294 | ||
|
|
cb3131a166 | ||
|
|
3105f514e4 | ||
|
|
395b427787 | ||
|
|
4d63c37c38 | ||
|
|
a2776ade81 | ||
|
|
5f5b3f3d4c | ||
|
|
60b76c53fc | ||
|
|
e55ea8b126 | ||
|
|
889581e35b | ||
|
|
f7222d43c9 | ||
|
|
1e474c9689 | ||
|
|
50fb658776 | ||
|
|
dde0f3a403 | ||
|
|
597d7bd532 | ||
|
|
aa27f93a9c | ||
|
|
ae4b5231bb | ||
|
|
28ef42a424 | ||
|
|
70233ea903 | ||
|
|
63c15c2c8d | ||
|
|
3e1f387b2b | ||
|
|
77c777512c | ||
|
|
02059fb663 | ||
|
|
3205429d24 | ||
|
|
aa8eb9522f | ||
|
|
5030157246 | ||
|
|
a3bc9251bf | ||
|
|
5a325cfa7b | ||
|
|
583d3b5580 | ||
|
|
43e3663721 | ||
|
|
9f8a512eb5 | ||
|
|
3bcb322156 | ||
|
|
1e645cabd4 | ||
|
|
ee82763d45 | ||
|
|
42812078c5 | ||
|
|
83f0c3d1dd | ||
|
|
e5a70744c0 | ||
|
|
5eefdc6485 | ||
|
|
4d2bcbc583 | ||
|
|
299c4bda1b | ||
|
|
f4b9291d42 | ||
|
|
b7afc905ec | ||
|
|
01bd846433 | ||
|
|
08f717d4fc | ||
|
|
b9fd87b004 | ||
|
|
1615f2c79a | ||
|
|
f430db0de7 | ||
|
|
32eb603643 | ||
|
|
c3f387f22a | ||
|
|
8703caff5f | ||
|
|
c5d50c9e47 | ||
|
|
fed4e3e03a | ||
|
|
9d1f73e179 | ||
|
|
ba164d9488 | ||
|
|
3fe67eb646 | ||
|
|
12ba2c30b9 | ||
|
|
7c1b41019e | ||
|
|
707110e5a7 | ||
|
|
ba9a9cb016 | ||
|
|
c1c75c4b67 | ||
|
|
0446349b89 | ||
|
|
915cb44601 | ||
|
|
17a153fb6d | ||
|
|
e339e897ff | ||
|
|
6b57f163bd | ||
|
|
4ace4819ff | ||
|
|
ce893122af | ||
|
|
fb5188a8c6 | ||
|
|
c17f452fc7 | ||
|
|
71b0f54b7a | ||
|
|
d387d021fe | ||
|
|
d6fefc3603 | ||
|
|
efb8a29b5f | ||
|
|
ff100a499a | ||
|
|
d89dc65330 | ||
|
|
fa41527f85 | ||
|
|
f48d844e42 | ||
|
|
898df6287a | ||
|
|
2522d42c71 | ||
|
|
39c5e85564 | ||
|
|
1294c05a91 | ||
|
|
64f802d4f6 | ||
|
|
61e782389c | ||
|
|
7cfb230a5e | ||
|
|
0e2af40329 | ||
|
|
7f51ff0a8d | ||
|
|
d1a61c6dce | ||
|
|
c90d1fc8ef | ||
|
|
42cd046e90 | ||
|
|
52fa350138 | ||
|
|
4ea8357c6a | ||
|
|
dd0da70b06 | ||
|
|
d80f2a621d | ||
|
|
16082456df | ||
|
|
49cc69ecc5 | ||
|
|
a0c8e1959a | ||
|
|
c7010dac3c | ||
|
|
99bfc3aaa0 | ||
|
|
43b3922803 | ||
|
|
ca70ad1a9f | ||
|
|
a250419b59 | ||
|
|
291644f29d | ||
|
|
d4e97ab64c | ||
|
|
e92f98d3c6 | ||
|
|
999aac19de | ||
|
|
b2f6e5673d | ||
|
|
f0d1c962a7 | ||
|
|
6999b8d9b4 | ||
|
|
46e704d507 | ||
|
|
308e94ea79 | ||
|
|
0c839b2738 | ||
|
|
cff5859c59 | ||
|
|
6d95f5fc98 | ||
|
|
7684861249 | ||
|
|
9759cb7075 | ||
|
|
b3a5f9bef4 | ||
|
|
3e3b6cc1e1 | ||
|
|
474103dc82 | ||
|
|
092a8f2d05 | ||
|
|
2bcf0c354a | ||
|
|
73cc756cac | ||
|
|
6091c2dba0 | ||
|
|
2862a73253 | ||
|
|
850c3f2b6a | ||
|
|
98f3e4cbd3 | ||
|
|
efc8ed4845 | ||
|
|
0bc4c7d1a0 | ||
|
|
be2e754d78 | ||
|
|
817e72846e | ||
|
|
220768bffc | ||
|
|
3cd64bcb22 | ||
|
|
86bfb07c29 | ||
|
|
ad08bd62aa | ||
|
|
d79cab0680 | ||
|
|
d1d6f7d838 | ||
|
|
e31a7e5c9d | ||
|
|
e6f0d9887c | ||
|
|
2855d84fba | ||
|
|
3c19648a56 | ||
|
|
8db367c743 | ||
|
|
2c4fabba35 | ||
|
|
dff42ffb41 | ||
|
|
11d61a744d | ||
|
|
5cefdbf985 | ||
|
|
5485f96625 | ||
|
|
af0f46d23d | ||
|
|
c063fe0720 | ||
|
|
203ba7343c | ||
|
|
d889547b26 | ||
|
|
b66e19dc43 | ||
|
|
c84e3334bf | ||
|
|
d5eeb948d5 | ||
|
|
9670833a5d | ||
|
|
ca051e943f | ||
|
|
36d89d02e1 | ||
|
|
f4bfa77942 | ||
|
|
f2258d4202 | ||
|
|
d56bf34326 | ||
|
|
9fa3dee522 | ||
|
|
7ee2192c29 | ||
|
|
3a38292bab | ||
|
|
60cbb65d84 | ||
|
|
d118ab71e6 | ||
|
|
81a1aedeb9 | ||
|
|
1fd576436b | ||
|
|
fac05e7dcd | ||
|
|
eef3126f0b | ||
|
|
2df5a2a66d | ||
|
|
01e7e3c24a | ||
|
|
8112dee91e | ||
|
|
638f7a1c89 | ||
|
|
5de4c3cc3f | ||
|
|
6579007ca0 | ||
|
|
c596fb14bb | ||
|
|
116fc4e00d | ||
|
|
57f6f54f29 | ||
|
|
8640e6d1df | ||
|
|
801583fd07 | ||
|
|
4987534eba | ||
|
|
ed4bf1c13d | ||
|
|
5b24225251 | ||
|
|
886be8c452 | ||
|
|
269efb9c1e | ||
|
|
612448e4ae | ||
|
|
82db19d54c | ||
|
|
06aa3e6b8c | ||
|
|
abf985c69e | ||
|
|
c176b54f6b | ||
|
|
b24e691e7e | ||
|
|
c2e43dc1b0 | ||
|
|
7b7739c32c | ||
|
|
269172406f | ||
|
|
4c054d6de9 | ||
|
|
34a58369f2 | ||
|
|
59b4764a15 | ||
|
|
7ebba75fa2 | ||
|
|
b2e80efe3f | ||
|
|
b4b566318a | ||
|
|
27df896a9c | ||
|
|
8188a551f3 | ||
|
|
f13bff2a76 | ||
|
|
59f1c038fe | ||
|
|
006a409eb8 | ||
|
|
dec4ceabb5 | ||
|
|
4a902dbbbe | ||
|
|
8e488e2913 | ||
|
|
e58e27ce22 | ||
|
|
78c0926a64 | ||
|
|
4693069a06 | ||
|
|
70e529ef5d | ||
|
|
2a154f8c9a | ||
|
|
634ace552d | ||
|
|
751a1ba969 | ||
|
|
d95573741d | ||
|
|
faf4bcdd62 | ||
|
|
badae90051 | ||
|
|
a27c593a2a | ||
|
|
f699442bec | ||
|
|
8720931a53 | ||
|
|
600dcdfc58 | ||
|
|
a4b83327c2 | ||
|
|
8c1c49a45e | ||
|
|
b1f0014429 | ||
|
|
d984918c75 | ||
|
|
21ac4b5139 | ||
|
|
92eb7a0be4 | ||
|
|
b26b1c0820 | ||
|
|
a9dd6d6bdb | ||
|
|
d60c53cd12 | ||
|
|
6b0fe6e0a0 | ||
|
|
9c7ec55b40 | ||
|
|
28f1f4cbdc | ||
|
|
508b3ce730 | ||
|
|
87ecc61fb4 | ||
|
|
ce4d664abc | ||
|
|
45b41f0787 | ||
|
|
c47434634d | ||
|
|
b89355b9d8 | ||
|
|
3f40d6f7b7 | ||
|
|
155daac8ad | ||
|
|
f9d24d07dd | ||
|
|
d91e35e197 | ||
|
|
a967dd9d13 | ||
|
|
f4bb7bcbff | ||
|
|
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 | ||
|
|
78f150cfbc | ||
|
|
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 | ||
|
|
350e636e3d | ||
|
|
429140df97 | ||
|
|
f92d2e3f7c | ||
|
|
a9b75d059b | ||
|
|
e6f289deb6 | ||
|
|
0e22618d93 | ||
|
|
c5bb074573 | ||
|
|
4e8fc6d198 | ||
|
|
618d673947 | ||
|
|
4cd5529027 | ||
|
|
5ac08ec3aa |
7
.gitignore
vendored
Executable file → Normal file
7
.gitignore
vendored
Executable file → Normal file
@@ -33,8 +33,10 @@ apps/
|
||||
home.html
|
||||
# page header plugin
|
||||
pageheader.html
|
||||
# Ignore site TOS
|
||||
# Ignore site TOS & gddpr
|
||||
doc/SiteTOS.md
|
||||
doc/*/SiteTOS.md
|
||||
doc/*/gdpr.md
|
||||
# themes except for redbasic
|
||||
view/theme/*
|
||||
!view/theme/redbasic
|
||||
@@ -55,6 +57,7 @@ tests/results/
|
||||
.buildpath
|
||||
.externalToolBuilders
|
||||
.settings/
|
||||
.pydevproject
|
||||
# NetBeans project folder
|
||||
nbproject/
|
||||
# Kdevelop project files
|
||||
@@ -75,3 +78,5 @@ composer.phar
|
||||
vendor/**/tests/
|
||||
vendor/**/Test/
|
||||
vendor/sabre/*/examples/
|
||||
# /info is a directory containing site-specific HTML documents
|
||||
/info/
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Select image from https://hub.docker.com/_/php/
|
||||
#image: php:7.2
|
||||
#image: php:7.3
|
||||
# Use a prepared Hubzilla image to optimise pipeline duration
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.2
|
||||
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
|
||||
stages:
|
||||
- test
|
||||
@@ -41,7 +40,8 @@ before_script:
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php ./composer.phar install --no-progress
|
||||
|
||||
# php.ini settings
|
||||
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
|
||||
|
||||
# hidden job definition with template for MySQL/MariaDB
|
||||
.job_template_mysql: &job_definition_mysql
|
||||
@@ -82,23 +82,23 @@ before_script:
|
||||
- tests/results/
|
||||
|
||||
|
||||
# PHP7.2 with MySQL 5.7
|
||||
php7.2_mysql5.7:
|
||||
# PHP7.3 with MySQL 5.7
|
||||
php7.3_mysql5.7:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- mysql:5.7
|
||||
|
||||
|
||||
# PHP7.2 with MySQL 8 (latest)
|
||||
php7.2_mysql8:
|
||||
# PHP7.3 with MySQL 8 (latest)
|
||||
php7.3_mysql8:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- name: mysql:8
|
||||
command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
|
||||
|
||||
# PHP7.2 with MariaDB 10.2
|
||||
php7.2_mariadb10.2:
|
||||
# PHP7.3 with MariaDB 10.2
|
||||
php7.3_mariadb10.2:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- name: mariadb:10.2
|
||||
@@ -114,8 +114,8 @@ php7.3_mariadb10.3:
|
||||
alias: mysql
|
||||
|
||||
|
||||
# PHP7.2 with PostgreSQL latest (11)
|
||||
php7.2_postgres11:
|
||||
# PHP7.3 with PostgreSQL latest (11)
|
||||
php7.3_postgres11:
|
||||
<<: *job_definition_postgres
|
||||
artifacts: *artifacts_template
|
||||
|
||||
|
||||
@@ -1,49 +1,10 @@
|
||||
# Hubzilla at Home next to your Router
|
||||
|
||||
This readme will show you how to install and run Hubzilla or Zap at home.
|
||||
|
||||
The installation is done by a script.
|
||||
|
||||
What the script will do for you...
|
||||
|
||||
+ install everything required by Zap/Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||
+ create a database
|
||||
+ run certbot to have everything for a secure connection (httpS)
|
||||
+ create a script for daily maintenance
|
||||
- backup to external disk (certificates, database, /var/www/)
|
||||
- renew certfificate (letsencrypt)
|
||||
- update of Zap/Hubzilla
|
||||
- update of Debian
|
||||
- restart
|
||||
+ create cron jobs for
|
||||
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
|
||||
- Master.php for Zap/Hubzilla every 10 minutes
|
||||
- daily maintenance script every day at 05:30
|
||||
|
||||
The script is known to work without adjustments with
|
||||
|
||||
+ Hardware
|
||||
- Mini-PC with Debian 9 (stretch), or
|
||||
- Rapberry 3 with Raspbian, Debian 9
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
- freedns.afraid.org
|
||||
|
||||
The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project) and [Zap](https://zotlabs.com/zap/). Make sure to use the correct GIT repositories.
|
||||
|
||||
+ Hubzilla
|
||||
- core: git clone https://framagit.org/hubzilla/core.git html (in this readme)
|
||||
- addons: util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons (in hubzilla-setup.sh)
|
||||
+ Zap
|
||||
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
|
||||
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
|
||||
# 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
|
||||
|
||||
@@ -55,66 +16,99 @@ Hardware
|
||||
|
||||
Software
|
||||
|
||||
+ Fresh installation of Debian 9 (Stretch)
|
||||
+ 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
|
||||
- Prepare your external disk for backups
|
||||
- hubzilla-setup.sh as root
|
||||
- ... wait, wait, wait until the script is finised
|
||||
+ 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
|
||||
- ./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 Software
|
||||
Do this just before you register the first user.
|
||||
|
||||
## Install Debian 9
|
||||
In Admin settings of your hub/instance or via terminal
|
||||
|
||||
Provided you use a Raspberry Pi 3...
|
||||
cd /var/www/html
|
||||
|
||||
Download the OS Raspbian from https://www.raspberrypi.org/downloads/raspbian/
|
||||
Check the current setting
|
||||
|
||||
Follow the installation instruction there.
|
||||
util/config system verify_email
|
||||
|
||||
Switch the verification on/off (1/0)
|
||||
|
||||
util/config system verify_email 0
|
||||
|
||||
## What the script will do for you...
|
||||
|
||||
+ 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
|
||||
|
||||
The script is known to work without adjustments with
|
||||
|
||||
+ 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
|
||||
|
||||
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.
|
||||
|
||||
|
||||
# Step-by-Step - some Details
|
||||
|
||||
## Preparations
|
||||
|
||||
## Configure your Router
|
||||
|
||||
Your web has to be visible in the internet.
|
||||
Your webserver has to be visible in the internet.
|
||||
|
||||
Open the ports 80 and 443 on your router for your Debian. Make sure your web server is marked as "exposed host".
|
||||
|
||||
## Preparations Dynamic IP Address
|
||||
|
||||
Follow the instructions in .homeinstall/hubzilla-config.txt.
|
||||
Follow the instructions in .homeinstall/zotserver-config.txt.
|
||||
|
||||
In short...
|
||||
|
||||
Your Hubzilla must be reachable by a domain that you can type in your browser
|
||||
Your Hubzilla server must be reachable by a domain that you can type in your browser
|
||||
|
||||
cooldomain.org
|
||||
|
||||
@@ -136,8 +130,6 @@ The cost is 1,50 € per month (2019).
|
||||
|
||||
## Note on Rasperry
|
||||
|
||||
The script was tested with an Raspberry 3 under Raspian, Debian 9.
|
||||
|
||||
It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
sudo raspi-config
|
||||
@@ -146,12 +138,6 @@ to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
On a Raspian Stretch (Debian 9) the validation of the mail address fails for the very first 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,163 +0,0 @@
|
||||
###############################################
|
||||
### MANDATORY - database password #############
|
||||
#
|
||||
# Please give your database password
|
||||
# It is better to not use blanks inside the password.
|
||||
# Example: db_pass=pass_word_with_no_blanks_in_it
|
||||
db_pass=
|
||||
|
||||
###############################################
|
||||
### MANDATORY - let's encrypt #################
|
||||
#
|
||||
# Hubilla 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
|
||||
#
|
||||
# Example: my.cooldomain.org
|
||||
# Example: cooldomain.org
|
||||
#
|
||||
# You might use "localhost" for a LOCAL TEST installation.
|
||||
# This is usefull if you want to debug the server inside a VM.
|
||||
#
|
||||
# Example: localhost
|
||||
#
|
||||
# Email is optional if you use "localhost".
|
||||
#
|
||||
#
|
||||
le_domain=
|
||||
le_email=
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - selfHOST - dynamic IP address ##
|
||||
#
|
||||
# 1. Register a domain at selfhost.de
|
||||
# - choose offer "DOMAIN dynamisch" 1,50€/mon at 04/2019
|
||||
# 2. Get your configuration for dynamic IP update
|
||||
# - Log in at selfhost.de
|
||||
# - go to "DynDNS Accounte"
|
||||
# - klick "Details" of your (freshly) registered domain
|
||||
# - You will find the configuration there
|
||||
# - Benutzername (user name) > use this for "selfhost_user="
|
||||
# - Passwort (pass word) > use this for "selfhost_pass="
|
||||
#
|
||||
#
|
||||
selfhost_user=
|
||||
selfhost_pass=
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - FreeDNS - dynamic IP address ###
|
||||
#
|
||||
# Please give the alpha-numeric-key of freedns
|
||||
#
|
||||
# Get a free subdomain from freedns and use it for your dynamic ip address
|
||||
# Documentation under http://www.techjawab.com/2013/06/setup-dynamic-dns-dyndns-for-free-on.html
|
||||
#
|
||||
# - Register for a Free domain at http://freedns.afraid.org/signup/
|
||||
# - WATCH THIS: Make sure you choose a domain with as less subdomains as
|
||||
# possible. Why? Let's encrpyt issues a limited count of certificates each
|
||||
# day. Possible other users of this domain will try to issue a certificate
|
||||
# at the same day.
|
||||
# - Logon to FreeDNS (where you just registered)
|
||||
# - Goto http://freedns.afraid.org/dynamic/
|
||||
# - Right click on "Direct Link" and copy the URL and paste it somewhere.
|
||||
# - You should notice a large and unique alpha-numeric key in the URL
|
||||
#
|
||||
# http://freedns.afraid.org/dynamic/update.php?alpha-numeric-key
|
||||
#
|
||||
# Provided your url from freedns is
|
||||
#
|
||||
# http://freedns.afraid.org/dynamic/update.php?U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5
|
||||
#
|
||||
# Then you have to provide
|
||||
#
|
||||
# freedns_key=U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5
|
||||
#
|
||||
#
|
||||
freedns_key=
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - Backup to external device ######
|
||||
#
|
||||
# The script can use an external device for the daily backup.
|
||||
# The file system of the device (USB stick for example) must be compatible with
|
||||
#
|
||||
# - encrypted LUKS + ext4, or
|
||||
# - ext4
|
||||
#
|
||||
# You should test to mount the device befor you run the script
|
||||
# (hubzilla-setup.sh).
|
||||
# How to find your (pluged-in) devices?
|
||||
#
|
||||
# fdisk -l
|
||||
#
|
||||
# Provided your device was listed as is /dev/sdb1. You could check with:
|
||||
#
|
||||
# blkid | grep /dev/sdb1
|
||||
#
|
||||
# Try to decrypt
|
||||
# (You might install cryptsetup befor using apt-get install.
|
||||
#
|
||||
# apt-get install cryptsetup
|
||||
# cryptsetup luksOpen /dev/sdb1 cryptobackup
|
||||
#
|
||||
# Try to mount
|
||||
# You might create the directory /media/hubzilla_backup it it does not exist
|
||||
# using mkdir.
|
||||
#
|
||||
# mkdir /media/hubzilla_backup
|
||||
# mount /dev/mapper/cryptobackup /media/hubzilla_backup
|
||||
#
|
||||
# Unmounting device goes like this
|
||||
#
|
||||
# umount /media/hubzilla_backup
|
||||
# cryptsetup luksClose cryptobackup
|
||||
#
|
||||
# To check if still mounted
|
||||
#
|
||||
# lsof /media/hubzilla_backup
|
||||
#
|
||||
# If you leave the following parameters
|
||||
#
|
||||
# - "backup_device_name" and
|
||||
# - "backup_device_pass"
|
||||
#
|
||||
# empty the script will create daily backups on the internal disk (which could
|
||||
# save you as well).
|
||||
#
|
||||
# Example: backup_device_name=/dev/sdc1
|
||||
#
|
||||
# Leave "backup_device_pass=" empty if the external device is not encrypted.
|
||||
#
|
||||
backup_device_name=
|
||||
backup_device_pass=
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - do not mess with things below ##
|
||||
# (...if you are not certain)
|
||||
#
|
||||
# Usually you are done here
|
||||
# Everything below is OPTIONAL
|
||||
#
|
||||
###############################################
|
||||
#
|
||||
# Database for hubzilla
|
||||
hubzilla_db_name=hubzilla
|
||||
hubzilla_db_user=hubzilla
|
||||
hubzilla_db_pass=$db_pass
|
||||
#
|
||||
#
|
||||
# Password for package mysql-server
|
||||
# Example: mysqlpass=aberhallo
|
||||
# Example: mysqlpass="aber hallo has blanks in it"
|
||||
#
|
||||
mysqlpass=$db_pass
|
||||
|
||||
# Password for package phpmyadmin
|
||||
# Example: phpmyadminpass=aberhallo
|
||||
# Example: phpmyadminpass="aber hallo has blanks in it"
|
||||
phpmyadminpass=$db_pass
|
||||
|
||||
@@ -1,681 +0,0 @@
|
||||
#!/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/
|
||||
# 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 addon
|
||||
# - download hubzilla core and addons
|
||||
# - configure cron
|
||||
# * "Master.php" for regular background prozesses of hubzilla
|
||||
# * "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 hubzillas database and files (rsync)
|
||||
# - letsencrypt
|
||||
#
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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?
|
||||
#
|
||||
# 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/ > hubzilla/zap from github
|
||||
# - /etc/letsencrypt/ > certificates
|
||||
#
|
||||
# hubzilla-daily.sh writes the backup to an external disk compatible to LUKS+ext4 (see hubzilla-config.txt)
|
||||
#
|
||||
# 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 php-mysqli php-mbstring php-xml"
|
||||
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 "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
|
||||
# check if user gave mail address
|
||||
if [ -z "$le_email" ]
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
||||
fi
|
||||
nocheck_install "apt-transport-https"
|
||||
# add backports to your sources.list
|
||||
backports_list=/etc/apt/sources.list.d/backports.list
|
||||
if [ -f $backports_list ]
|
||||
then
|
||||
print_info "$backports_list exist already"
|
||||
else
|
||||
echo "deb https://deb.debian.org/debian stretch-backports main" > $backports_list
|
||||
fi
|
||||
apt-get -y update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -q -y -t stretch-backports install certbot python-certbot-apache
|
||||
print_info "run certbot ..."
|
||||
certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
|
||||
service apache2 restart
|
||||
}
|
||||
|
||||
function check_https {
|
||||
print_info "checking httpS > testing ..."
|
||||
url_https=https://$le_domain
|
||||
wget_output=$(wget -nv --spider --max-redirect 0 $url_https)
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
print_warn "check not ok"
|
||||
else
|
||||
print_info "check ok"
|
||||
fi
|
||||
}
|
||||
|
||||
function install_hubzilla {
|
||||
print_info "installing hubzilla addons..."
|
||||
cd /var/www/html/
|
||||
# if you install Hubzilla
|
||||
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
|
||||
# if you install ZAP
|
||||
#util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
|
||||
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
|
||||
print_info "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 install_rsync {
|
||||
print_info "installing rsync..."
|
||||
nocheck_install "rsync"
|
||||
}
|
||||
|
||||
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 'Master.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
|
||||
# - renew the certificate of letsencrypt
|
||||
# - backup db, files (/var/www/html), certificates if letsencrypt
|
||||
# - update hubzilla 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/$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 "certbot renew --noninteractive" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - stopping apache and mysql...\"" >> /var/www/$hubzilladaily
|
||||
echo "service apache2 stop" >> /var/www/$hubzilladaily
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /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 " rsync -a --delete /var/lib/mysql/ /media/hubzilla_backup/mysql" >> /var/www/$hubzilladaily
|
||||
echo " rsync -a --delete /var/www/ /media/hubzilla_backup/www" >> /var/www/$hubzilladaily
|
||||
echo " rsync -a --delete /etc/letsencrypt/ /media/hubzilla_backup/letsencrypt" >> /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 core and addons...\"" >> /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 and update finished. Rebooting...\"" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "shutdown -r now" >> /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"
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# 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
|
||||
backup_mount_point=/media/hubzilla_backup
|
||||
|
||||
#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
|
||||
check_https
|
||||
else
|
||||
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
|
||||
fi
|
||||
|
||||
install_hubzilla
|
||||
|
||||
configure_cron_daily
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_rsync
|
||||
install_cryptosetup
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
178
.homeinstall/zotserver-config.txt.template
Normal file
178
.homeinstall/zotserver-config.txt.template
Normal file
@@ -0,0 +1,178 @@
|
||||
###############################################
|
||||
### MANDATORY - database password #############
|
||||
#
|
||||
# Please give your database password
|
||||
# It is better to not use blanks inside the password.
|
||||
# Example: db_pass=pass_word_with_no_blanks_in_it
|
||||
db_pass=
|
||||
|
||||
###############################################
|
||||
### MANDATORY - let's encrypt #################
|
||||
#
|
||||
# Zot requires encrypted communication via secure HTTP (HTTPS).
|
||||
# This script automates installation of an SSL certificate from
|
||||
# Let's Encrypt (https://letsencrypt.org)
|
||||
#
|
||||
# Please give the domain name of your hub/instance
|
||||
#
|
||||
# Example: my.cooldomain.org
|
||||
# Example: cooldomain.org
|
||||
#
|
||||
# You might use "localhost" for a LOCAL TEST installation.
|
||||
# This is usefull if you want to debug the server inside a VM.
|
||||
#
|
||||
# Example: localhost
|
||||
#
|
||||
# Email is optional if you use "localhost".
|
||||
#
|
||||
#
|
||||
le_domain=
|
||||
le_email=
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - 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 04/2019
|
||||
# 2. Get your configuration for dynamic IP update
|
||||
# - Log in at selfhost.de
|
||||
# - go to "DynDNS Accounte"
|
||||
# - klick "Details" of your (freshly) registered domain
|
||||
# - You will find the configuration there
|
||||
# - Benutzername (user name) > use this for "selfhost_user="
|
||||
# - Passwort (pass word) > use this for "selfhost_pass="
|
||||
#
|
||||
#
|
||||
selfhost_user=
|
||||
selfhost_pass=
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - FreeDNS - dynamic IP address ###
|
||||
#
|
||||
# Please give the alpha-numeric-key of freedns
|
||||
#
|
||||
# Get a free subdomain from freedns and use it for your dynamic ip address
|
||||
# Documentation under http://www.techjawab.com/2013/06/setup-dynamic-dns-dyndns-for-free-on.html
|
||||
#
|
||||
# - Register for a Free domain at http://freedns.afraid.org/signup/
|
||||
# - WATCH THIS: Make sure you choose a domain with as less subdomains as
|
||||
# possible. Why? Let's encrpyt issues a limited count of certificates each
|
||||
# day. Possible other users of this domain will try to issue a certificate
|
||||
# at the same day.
|
||||
# - Logon to FreeDNS (where you just registered)
|
||||
# - Goto http://freedns.afraid.org/dynamic/
|
||||
# - Right click on "Direct Link" and copy the URL and paste it somewhere.
|
||||
# - You should notice a large and unique alpha-numeric key in the URL
|
||||
#
|
||||
# http://freedns.afraid.org/dynamic/update.php?alpha-numeric-key
|
||||
#
|
||||
# Provided your url from freedns is
|
||||
#
|
||||
# http://freedns.afraid.org/dynamic/update.php?U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5
|
||||
#
|
||||
# Then you have to provide
|
||||
#
|
||||
# freedns_key=U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5
|
||||
#
|
||||
#
|
||||
freedns_key=
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - Backup to external device ######
|
||||
#
|
||||
# The script can use an external device for the daily backup.
|
||||
# The file system of the device (USB stick for example) must be compatible with
|
||||
#
|
||||
# - encrypted LUKS + ext4, or
|
||||
# - ext4
|
||||
#
|
||||
# You should test to mount the device before you run the script
|
||||
# (hubzilla-setup.sh).
|
||||
# How to find your (pluged-in) devices?
|
||||
#
|
||||
# fdisk -l
|
||||
#
|
||||
# Provided your device was listed as is /dev/sdb1. You could check with:
|
||||
#
|
||||
# blkid | grep /dev/sdb1
|
||||
#
|
||||
# Try to decrypt
|
||||
# (You might install cryptsetup befor using apt-get install.
|
||||
#
|
||||
# apt-get install cryptsetup
|
||||
# cryptsetup luksOpen /dev/sdb1 cryptobackup
|
||||
#
|
||||
# Try to mount
|
||||
# You might create the directory /media/hubzilla_backup it it does not exist
|
||||
# using mkdir.
|
||||
#
|
||||
# mkdir /media/hubzilla_backup
|
||||
# mount /dev/mapper/cryptobackup /media/hubzilla_backup
|
||||
#
|
||||
# Unmounting device goes like this
|
||||
#
|
||||
# umount /media/hubzilla_backup
|
||||
# cryptsetup luksClose cryptobackup
|
||||
#
|
||||
# To check if still mounted
|
||||
#
|
||||
# lsof /media/hubzilla_backup
|
||||
#
|
||||
# If you leave the following parameters
|
||||
#
|
||||
# - "backup_device_name" and
|
||||
# - "backup_device_pass"
|
||||
#
|
||||
# empty the script will create daily backups on the internal disk (which could
|
||||
# save you as well).
|
||||
#
|
||||
# Example: backup_device_name=/dev/sdc1
|
||||
#
|
||||
# Leave "backup_device_pass=" empty if the external device is not encrypted.
|
||||
#
|
||||
backup_device_name=
|
||||
backup_device_pass=
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - do not mess with things below ##
|
||||
# (...if you are not certain)
|
||||
#
|
||||
# Usually you are done here
|
||||
# Everything below is OPTIONAL
|
||||
#
|
||||
###############################################
|
||||
#
|
||||
# Database for your hub/instance
|
||||
# If left empty, both your database and user will be named after your zot instance (hubzilla, zap or misty)
|
||||
# Use custom name, at least fo the database, if you plan to run more than one hub/instance on the same server
|
||||
#
|
||||
zotserver_db_name=
|
||||
zotserver_db_user=
|
||||
zotserver_db_pass=$db_pass
|
||||
#
|
||||
#
|
||||
# Password for package mysql-server
|
||||
# Example: mysqlpass=aberhallo
|
||||
# Example: mysqlpass="aber hallo has blanks in it"
|
||||
#
|
||||
mysqlpass=$db_pass
|
||||
|
||||
# Password for package phpmyadmin
|
||||
# Example: phpmyadminpass=aberhallo
|
||||
# Example: phpmyadminpass="aber hallo has blanks in it"
|
||||
phpmyadminpass=$db_pass
|
||||
|
||||
793
.homeinstall/zotserver-setup.sh
Normal file
793
.homeinstall/zotserver-setup.sh
Normal 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
|
||||
0
.openshift/action_hooks/deploy
Executable file → Normal file
0
.openshift/action_hooks/deploy
Executable file → Normal file
0
.openshift/cron/weekly/chronograph
Executable file → Normal file
0
.openshift/cron/weekly/chronograph
Executable file → Normal file
694
CHANGELOG
694
CHANGELOG
@@ -1,3 +1,591 @@
|
||||
Hubzilla 6.0 (2021-07-09)
|
||||
- Implement swipe to right for bringing in left aside
|
||||
- DB update 1247 to clean up bogus entries in updates
|
||||
- DB update 1246 to mark legacy zot xchans and hublocs deleted
|
||||
- Implement desktop notifications
|
||||
- Emit a warning if the calendar for the created event is disabled
|
||||
- Add an option to drop media for bbcode processing
|
||||
- Make mod HQ the default landing page after login
|
||||
- Implement direct messages view for mod HQ
|
||||
- Implement public/restricted messages view for mod HQ
|
||||
- Implement starred messages view for mod HQ (only available if the Star Posts feature is enabled)
|
||||
- Update composer libs
|
||||
- Remove deprecated mod ping
|
||||
- Remove legacy zot libs and functions - major cleanup
|
||||
|
||||
Bugfixes
|
||||
- Fix deleting and starring in unthreaded view
|
||||
- Fix issue where incomplete datasets were stored into updates
|
||||
- Fix photo item tags not stored and propagated
|
||||
- Fix notifications not loading if a filter was applied
|
||||
- Fix in browser email validation for registrations
|
||||
- Fix directory sync issues
|
||||
- Fix issue where the original rawmsg iconfig got overwritten
|
||||
- Fix unmaintained id3 pareser for PHP8
|
||||
- Fix item_private state for imported items
|
||||
- Random PHP8 fixes (ongoing)
|
||||
|
||||
Addons
|
||||
- Pubcrawl: fix ld-signature for profile updates
|
||||
- Pubcrawl: deprecate as_actor_store() in favor of Activity::actor_store()
|
||||
- Twitter: prevent duplicated tweets
|
||||
- Remove legacy zot dpendencies and deprecated functions
|
||||
- Pubcrawl: fix remote reply for peertube
|
||||
- Pubcrawl: fix issue where we could end up with an xchan but without hubloc
|
||||
- Diaspora: implement the direct_message_recipients hook
|
||||
- Queueworker: add a simple priority mechanism to prevent not so important janitor tasks (e.g. onedirsync) stuffing up the queue and delaying delivery of items
|
||||
- Pubcrawl: implement direct message recognision for activities coming from Mastodon
|
||||
- Pubcrawl: always show complete threads (complete as in all the messages we have received) in public stream
|
||||
- Twitter_api: remove the mail endpoint
|
||||
- Mail: make interface read only with the possibility to download and delete mails (this addon will be removed in a future version)
|
||||
- Pubsubhubbub: move to addons-unmaintained
|
||||
- GNU-Social: move to addons-unmaintained
|
||||
- Fixes to reflect core notifier changes
|
||||
- Diaspora: refactor conversations a.k.a mail to implement direct messages infrastructure
|
||||
- Pubcrawl: allow hublocs to be upgraded from ostatus
|
||||
- Diaspora: fix issue where we could end up with an xchan but without hubloc
|
||||
|
||||
|
||||
Hubzilla 5.6.1 (2021-06-04)
|
||||
- Update spanish translations
|
||||
- Fix login name label if register email verification is disabled
|
||||
- Fix zotinfo issue with deleted channels
|
||||
- Make pubstream ordering configurable
|
||||
- Fix article summary duplicated when editing
|
||||
- Update polish translations
|
||||
- Fix admin setting for invitations not displayed correctly
|
||||
- Fix registration in invite only mode
|
||||
- Fix notifications not returning offset -1 when returning early
|
||||
- Fix direct messages for items imported via sync
|
||||
- Bring back the channel protocols hooks
|
||||
- Fix security headers switching
|
||||
- Fix magic auth for delegated channels
|
||||
- Introduce drop_query_params() for secure query parameter removal
|
||||
- PHP8 fixes (ongoing)
|
||||
- Fix menu wrapping regression
|
||||
|
||||
Addons
|
||||
- LDAPauth: fix regression creating an account
|
||||
- Twitter: allow feeds crossposting
|
||||
- Twitter: fix posting when post by default is disabled
|
||||
- Pubcrawl: add litepub directMessage attribute
|
||||
- Pubcrawl: allow xchan/hubloc upgrades from e.g. ostatus
|
||||
- Diaspora: fix possible issue with missing hublocs
|
||||
- Diaspora: refine dispatching of public of public items
|
||||
|
||||
|
||||
Hubzilla 5.6 (2021-05-11)
|
||||
- Improve postgres hubloc queries
|
||||
- Implement automatic duplicate singleton hubloc removal
|
||||
- Send author id, id_sig and key fields along with author/owner
|
||||
- Implement custom redis session backend
|
||||
- Improved registration workflow
|
||||
- Complete rewrite of the registration backend with many new features
|
||||
- Complete rewrite of the invite app
|
||||
- Update Spanish, Russian and Polish translations
|
||||
- Improved PHP8 compatibiliy (work in progress)
|
||||
|
||||
Bugfixes
|
||||
- Fix manual fetching of non-ascii domains
|
||||
- Fix revision not compared when importing items
|
||||
- Fix events not transformed to UTC when importing calendar
|
||||
- Fix timezone issue in mod cal
|
||||
- Fix profile photos not revalidated
|
||||
- Fix regression in caldav/carddav discovery
|
||||
- Fix caldav/carddav sync on remote access
|
||||
- Fix info and notice messages not bootstraped when using SSE
|
||||
- Fix URL including an @ treated like a webbie
|
||||
- Fix cover photo image issues on some mobile devices
|
||||
|
||||
Addons
|
||||
- Diaspora: improve performance when delivering public items
|
||||
- Diaspora: make sure to not process same contact more than once
|
||||
- Pubcrawl: make sure to not process same contact more than once
|
||||
- Pubcrawl: do not relay Like and Dislike activity
|
||||
- Pubcrawl: deprecate as_follow() in favour of core Activity::follow()
|
||||
- Pubcrawl: improved compatibility with mobilizon and xwiki
|
||||
- Pubcrawl: do not process follow/unfollw thread in as_create_note()
|
||||
- Diaspora: do not relay comments/likes of strangers if the thread-owner is local and does not allow comments/likes by strangers in the diaspora app settings
|
||||
|
||||
|
||||
Hubzilla 5.4.3 (2021-04-20)
|
||||
- Fix regression in mod notifications (only the last was visible)
|
||||
- Set Permissions-Policy: interest-cohort=() header by default
|
||||
- Fix xchans containing a % breaking get_forum_channels()
|
||||
- Fix webfinger if using a reverse proxy
|
||||
- Fix regression finding bookmarks
|
||||
- Fix zot6 hublocs import on channel import
|
||||
- Fix revision not checked in import_items()
|
||||
|
||||
|
||||
Hubzilla 5.4.2 (2021-03-15)
|
||||
- Fix translation plural variable
|
||||
- Fix issue with following/unfollowing a thread
|
||||
- Fix rendering of long text in xchan vcard
|
||||
- Fix local link for rss content if rewrite author is sets
|
||||
- Fix regression in mod display
|
||||
|
||||
Addons
|
||||
- Pubcrawl: fix issue with following/unfollowing a thread
|
||||
- Pubcrawl: more robust implementation of mastodon remote reply
|
||||
- Photocache: remove suffix from the cached photo URL
|
||||
|
||||
|
||||
Hubzilla 5.4.1 (2021-03-09)
|
||||
- Fix profile not found if not logged in
|
||||
- Fix summary not reset on cancel
|
||||
- Fix summary not saved with aoutosave draft
|
||||
- Fix unexpected trigger of buttons when pressing enter in input fields
|
||||
- Fix spanish plural expression
|
||||
- Fix undefined page-end on non dynamic pages
|
||||
|
||||
Addons
|
||||
- Pubcrawl: fix regression in pubcrawl_follow_mod_init()
|
||||
|
||||
|
||||
Hubzilla 5.4 (2021-03-08)
|
||||
- Add new connections to privacy group independend from the default privacy group settings
|
||||
- group_add() return group hash to save a lookup
|
||||
- Do not poll feeds if feed contacts setting is disabled
|
||||
- Deprecate sticky_kit library in favor of CSS position sticky solution
|
||||
- Trigger endless scroll loading at the end of content instead of end of window height
|
||||
- Implement experimental zap export compatibility
|
||||
- Deprecate the [summary] tag in favor of a separate input field for the summary
|
||||
- Adjust error reporting for PHP8
|
||||
- Rely on php.ini default value for pcre.backtrack_limit
|
||||
- PHP8 compatibility (experimental)
|
||||
- Introduce Lib/Crypto (ported from zap)
|
||||
- Introduce Lib/Keyutils which now implements phpseclib v2
|
||||
- Improve profile photo fetching
|
||||
- Introduce fetch_provider hook
|
||||
- Implement ActivityStreams discovery in mod profile
|
||||
- Implement ActivityStreams discovery in mod channel
|
||||
- Streamline OS folder and file permissions
|
||||
- Add polish translations
|
||||
- Implement ThreadListener in mod activity_match
|
||||
- Improve ThreadListener handling
|
||||
- Use mail envelope instead of lock icon for direct messages
|
||||
- Implement ASCollection in Libzot::fetch_conversation()
|
||||
- Invoke channel discovery by hash instead of address in mod channel
|
||||
- Implement manual public item import for zot6, activitypub and diaspora via search
|
||||
- Default photo storage to filesystem instead of DB for new installations
|
||||
- Support filesystem storage for xchan profile photos
|
||||
- Deprecate Daemon/Externals
|
||||
- Implement SQL query background caching
|
||||
- Process channel categories list in background
|
||||
- Port util/connect to Lib/Connect
|
||||
|
||||
Bugfixes
|
||||
- Fix visible/empty notifications for blocked contacts items
|
||||
- Fix issue where URL fragment was turned into hashtag if the hashtag existed elsewhere in the post (issue #1518)
|
||||
- Fix audio and video embeds for media sources without media format extension
|
||||
- Fix issue where zot package was saved in iconf instead of the decoded activity
|
||||
- Fix duplicate id in post preview
|
||||
- Fix display issue of restricted content in mod display
|
||||
- Fix issue where comments were not delivered to the public stream
|
||||
- Fix issue where profile photos were stored multiple times and remove duplicates
|
||||
- Fix pinned items sync between clones
|
||||
- Fix r_preview for list mode in mod channel and mod network
|
||||
|
||||
Addons
|
||||
- Pubcrawl: deal with mastodons remote replies
|
||||
- Diaspora: reduce xchan network confusion in several places
|
||||
- Diaspora: fix mentions if multiple xchan networks exists
|
||||
- Diaspora: fix comments on comments
|
||||
- Pubcrawl: do not re-use broken signed messages
|
||||
- Pubcrawl: fix parsing of images with description (core issue #1519)
|
||||
- Pubcrawl: use the signed message from the attachment (iconfig) when relaying
|
||||
- Diaspora: implement browser to browser encrypted messages as base64 encoded string
|
||||
- Pubcrawl: implement browser to browser encrypted messages as base64 encoded string
|
||||
- Diaspora: support post summary
|
||||
- Pubcrawl: fix summary aka content warning
|
||||
- PHP8 compatibility (experimental)
|
||||
- Tripleaes: removed
|
||||
- Reflect core crypto changes
|
||||
- Photocache: improve mimetype detection
|
||||
- Diaspora: implement mnanual fetch provider
|
||||
- Diaspora: implement send participation
|
||||
- Pubcrawl: deprecate pubcrawl_is_as_request() in favor of the core version in Lib/ActivityStreams
|
||||
- Diaspora: prefer zot identity for inbound comments if available
|
||||
- Pubcrawl: return zotfeed results in mod outbox
|
||||
- Queueworker: improved deduplication by adding a uuid
|
||||
- Superblock: fix syncing with clones regression
|
||||
- Queueworker: improve SQL query in GetWorkerCount()
|
||||
- Queueworker: fix issue in workersleep handling
|
||||
|
||||
|
||||
Hubzilla 5.2.2 (2021-02-13)
|
||||
- Fix issue with ping_site()
|
||||
|
||||
|
||||
Hubzilla 5.2.1 (2021-01-16)
|
||||
- Fix attach_upgrade() to catch all broken entries in attach
|
||||
- Fix collect_recipients() public policy filter for zot6
|
||||
- Fix leaking of duplicate tasks in queueworker
|
||||
|
||||
|
||||
Hubzilla 5.2 (2021-01-13)
|
||||
- Use libzotdir for directory
|
||||
- Streamline usage of channel url for keyId
|
||||
- Basic work on PHP8 compatibility
|
||||
- Improve performance for forum post edit action
|
||||
- Improve File App tiles view
|
||||
- Update es strings
|
||||
- Update ru strings
|
||||
- Implement directory download via zip files in Files App
|
||||
- Implement bulk file download via zip files in Files App
|
||||
- Deprecate ! and !! forum tags - use direct messages to post to forums
|
||||
- Do not show forums where we do not have permission to post in ACL selector
|
||||
- Implement lockview for Files App
|
||||
- Implement file and directory rename functionality Files App
|
||||
- Implement file and directory copy functionality in Files App
|
||||
- Implement file and directory move functionality in Files App
|
||||
- Implement categories for files and directories in Files App
|
||||
- Implement drag and drop move action for files and directories in Files App
|
||||
- Implement bulk file actions for move, copy, categories and permissions
|
||||
- Implement a files categories widget
|
||||
- Implement a breadcrumb view for file paths
|
||||
- Rewrite xchan_vcard template
|
||||
- Update composer libs
|
||||
|
||||
Bugfixes
|
||||
- Fix direct messages by forum channel turned into group item
|
||||
- Fix ID3Parser composer autoload
|
||||
- Fix issue where directory_fallback_servers were not accessible from static function
|
||||
- Fix missing constant defenition for HUBLOC_OFFLINE
|
||||
- Fix sync_directories() including known dead sites
|
||||
- Fix undefined variable in poller preventing Onedirsync from running
|
||||
- Fix w2w posts not editable/deletable from local server
|
||||
- Fix issue where categories were not saved on forum wall posts
|
||||
- Fix no channel_id provided for contact_remove() in reply_purge()
|
||||
- Fix typo in notifier command
|
||||
- Fix profile title/description allowed more than 191 characters
|
||||
|
||||
Addons
|
||||
- Queueworker: cleanup whitespace
|
||||
- Queueworker: add some tweaks to prevent deadlocks for postgresql
|
||||
- Flashcards: compatibility for the changes in the Files App
|
||||
- Openstreemap: fix hostname parsing from URL
|
||||
- Openstreemap: fix content security policy
|
||||
- Pubcrawl: fix peertube video display
|
||||
- Pubcrawl: deliver updates to anyone owning the item
|
||||
|
||||
|
||||
Hubzilla 5.0.8 (2020-12-30)
|
||||
- Fix single quotes not escaped in the notifications title (issue 1503)
|
||||
- Return zot6 xchans for random_profile()
|
||||
- Return zot6 entries in dirsearch
|
||||
- Fix comment sync issue
|
||||
- Fix duplicate entries in contact autocomplete
|
||||
- Fix issue where direct message notifications where not displayed for wall items
|
||||
- Do not revalidate cached photos
|
||||
- Implement imagemagic resource consumption limiting
|
||||
- Specify key in mod owa
|
||||
- Fix issue where array was passed to get_key()
|
||||
|
||||
|
||||
Hubzilla 5.0.7 (2020-12-21)
|
||||
- Fix CardDAV addressbook ID
|
||||
- Use Zot6 for CardDAV and CalDAV sync between clones
|
||||
- Handle owa with hubloc_id_url only
|
||||
- Fix attachment in comment not visible after commenting - issue #1499
|
||||
|
||||
|
||||
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
|
||||
@@ -73,7 +661,7 @@ Hubzilla 4.2 (2019-06-04)
|
||||
|
||||
Hubzilla 4.0.3 (2019-04-26)
|
||||
- Add attachments to zot6 event objects
|
||||
- Add zot6 to federated transports
|
||||
- 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
|
||||
@@ -126,7 +714,7 @@ Hubzilla 4.0.1 (2019-03-21)
|
||||
- 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()
|
||||
@@ -340,7 +928,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
|
||||
@@ -356,7 +944,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.
|
||||
@@ -414,7 +1002,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
|
||||
@@ -473,7 +1061,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
|
||||
@@ -486,9 +1074,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
|
||||
@@ -530,8 +1118,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()
|
||||
@@ -1093,10 +1681,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)
|
||||
@@ -1104,18 +1692,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
|
||||
@@ -1127,7 +1715,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
|
||||
@@ -1193,7 +1781,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)
|
||||
@@ -1547,10 +2135,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
|
||||
@@ -1575,7 +2163,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.
|
||||
@@ -1583,7 +2171,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
|
||||
@@ -1607,7 +2195,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
|
||||
@@ -1632,7 +2220,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
|
||||
@@ -1655,7 +2243,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
|
||||
@@ -1663,7 +2251,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
|
||||
@@ -1683,7 +2271,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
|
||||
@@ -1695,7 +2283,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.
|
||||
@@ -1704,7 +2292,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.)
|
||||
@@ -1712,7 +2300,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
|
||||
@@ -1726,24 +2314,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)
|
||||
@@ -1766,10 +2354,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
|
||||
@@ -1785,26 +2373,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
|
||||
@@ -1812,7 +2400,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).
|
||||
@@ -1822,7 +2410,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
|
||||
@@ -1844,7 +2432,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
|
||||
@@ -1897,11 +2485,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"
|
||||
|
||||
|
||||
|
||||
|
||||
48
CHANGELOG.air
Normal file
48
CHANGELOG.air
Normal file
@@ -0,0 +1,48 @@
|
||||
"air" is a branch name for revision of Account-Invite-Register at the Hubzilla project
|
||||
|
||||
Invite:
|
||||
* Rewritten and now language template driven
|
||||
* Selectable templates for the invite mails
|
||||
* Invitor may add personal notes in the mailtext
|
||||
+ Invite codes are bound to the recipients email address
|
||||
* Invite mod never more creates accounts
|
||||
* new db scheme for table register
|
||||
* existing register table will be migrated to the new schema even when detected at runtime
|
||||
* Bugfix: creating invite codes when admin only calls Invite w/o any further action
|
||||
* account library revision also together with invite mod
|
||||
* Depending on config: Users may send invitations also
|
||||
* Invitations expires, controlled by the invitor
|
||||
* Changed and new configs:
|
||||
* * invitation_only As usual before
|
||||
* * invitation_also Beside other registration policies, invitations may be used also
|
||||
* * invitation_max_per_day defaults 50, may be changed in adminUI admin>site
|
||||
* * invitation_max_per_user defaults 4
|
||||
* Requirements:
|
||||
* * Addon language has to be installed
|
||||
|
||||
Register:
|
||||
* Register panel (form) and js interaction changed
|
||||
* Unused registrations expire
|
||||
* Depending on config, anonymous registrations (w/o email) are supported
|
||||
* :... dont't panic, that may let grow security
|
||||
* Even anonymous users have to confirm their registration
|
||||
* Registrations may be enabled / disabled time driven for each day in the week (dudy)
|
||||
* Unsoliced registration floods may be blocked
|
||||
* Limited registrations from one single source ip
|
||||
* Using one additional log file, to easy interfare with f2b
|
||||
|
||||
Account:
|
||||
* An user account always becomes created only if all depending conditions are satisfied
|
||||
* AdminUI for site configuration, accounts and registrations enhancements
|
||||
* Still untouched, but accountUI needs enhanced async control in case for mass delete
|
||||
with deep level of recursion cascade of the dependencies (channels etc). An open TODO
|
||||
since years for instances with many much users and channels.
|
||||
|
||||
History:
|
||||
2020.03 Hubzilla Prod version 4.6 (master branch) of hubzilla/core was the base for AIR
|
||||
that was assigned Version 4.6.2 at sn/core
|
||||
2021.02 Hubzilla Prod version 5.2.1 (master branch) of hubzilla/core was new base for AIR
|
||||
that was assigned version 5.2.2 at sn/core (air.5)
|
||||
plus adjustment of hubzilla 5.2.2 (master) to sn/core (air.5) version 5.2.9
|
||||
|
||||
|
||||
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.
|
||||
|
||||
33
SBOM.md
Normal file
33
SBOM.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# 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|
|
||||
|brick/math|0.9.2.0|MIT|https://github.com/brick/math.git|
|
||||
|bshaffer/oauth2-server-php|1.11.1.0|MIT|https://github.com/bshaffer/oauth2-server-php.git|
|
||||
|commerceguys/intl|1.1.0.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|5.0.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|
|
||||
|pear/text_languagedetect|1.0.1.0|BSD-2-Clause|https://github.com/pear/Text_LanguageDetect.git|
|
||||
|phpseclib/phpseclib|2.0.30.0|MIT|https://github.com/phpseclib/phpseclib.git|
|
||||
|psr/log|1.1.4.0|MIT|https://github.com/php-fig/log.git|
|
||||
|ramsey/collection|1.1.3.0|MIT|https://github.com/ramsey/collection.git|
|
||||
|ramsey/uuid|4.1.1.0|MIT|https://github.com/ramsey/uuid.git|
|
||||
|sabre/dav|4.1.5.0|BSD-3-Clause|https://github.com/sabre-io/dav.git|
|
||||
|sabre/event|5.1.2.0|BSD-3-Clause|https://github.com/sabre-io/event.git|
|
||||
|sabre/http|5.1.1.0|BSD-3-Clause|https://github.com/sabre-io/http.git|
|
||||
|sabre/uri|2.2.1.0|BSD-3-Clause|https://github.com/sabre-io/uri.git|
|
||||
|sabre/vobject|4.3.5.0|BSD-3-Clause|https://github.com/sabre-io/vobject.git|
|
||||
|sabre/xml|2.2.3.0|BSD-3-Clause|https://github.com/sabre-io/xml.git|
|
||||
|simplepie/simplepie|1.5.6.0|BSD-3-Clause|https://github.com/simplepie/simplepie.git|
|
||||
|smarty/smarty|3.1.39.0|LGPL-3.0|https://github.com/smarty-php/smarty.git|
|
||||
|symfony/polyfill-ctype|1.23.0.0|MIT|https://github.com/symfony/polyfill-ctype.git|
|
||||
|twbs/bootstrap|4.6.0.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|
|
||||
|jquery/jquery|3.5.1.0|MIT|https://github.com/jquery/jquery.git|
|
||||
@@ -54,7 +54,7 @@ class AccessList {
|
||||
* * \e string \b channel_deny_gid => string of denied gids
|
||||
*/
|
||||
function __construct($channel) {
|
||||
if($channel) {
|
||||
if ($channel) {
|
||||
$this->allow_cid = $channel['channel_allow_cid'];
|
||||
$this->allow_gid = $channel['channel_allow_gid'];
|
||||
$this->deny_cid = $channel['channel_deny_cid'];
|
||||
@@ -99,7 +99,6 @@ class AccessList {
|
||||
$this->allow_gid = $arr['allow_gid'];
|
||||
$this->deny_cid = $arr['deny_cid'];
|
||||
$this->deny_gid = $arr['deny_gid'];
|
||||
|
||||
$this->explicit = $explicit;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Access;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Lib\PConfig;
|
||||
|
||||
/**
|
||||
@@ -39,10 +40,10 @@ class PermissionLimits {
|
||||
*/
|
||||
static public function Std_Limits() {
|
||||
$limits = [];
|
||||
$perms = Permissions::Perms();
|
||||
$perms = Permissions::Perms();
|
||||
|
||||
foreach($perms as $k => $v) {
|
||||
if(strstr($k, 'view'))
|
||||
foreach ($perms as $k => $v) {
|
||||
if (strstr($k, 'view'))
|
||||
$limits[$k] = PERMS_PUBLIC;
|
||||
else
|
||||
$limits[$k] = PERMS_SPECIFIC;
|
||||
@@ -77,14 +78,14 @@ class PermissionLimits {
|
||||
* * \b array with all permission limits, if $perm is not set
|
||||
*/
|
||||
static public function Get($channel_id, $perm = '') {
|
||||
if($perm) {
|
||||
if ($perm) {
|
||||
return intval(PConfig::Get($channel_id, 'perm_limits', $perm));
|
||||
}
|
||||
|
||||
PConfig::Load($channel_id);
|
||||
if(array_key_exists($channel_id, \App::$config)
|
||||
&& array_key_exists('perm_limits', \App::$config[$channel_id]))
|
||||
return \App::$config[$channel_id]['perm_limits'];
|
||||
if (array_key_exists($channel_id, App::$config)
|
||||
&& array_key_exists('perm_limits', App::$config[$channel_id]))
|
||||
return App::$config[$channel_id]['perm_limits'];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -214,13 +218,13 @@ class PermissionRoles {
|
||||
// set permissionlimits for this permission here, for example:
|
||||
|
||||
// if($perm === 'mynewperm')
|
||||
// \Zotlabs\Access\PermissionLimits::Set($uid,$perm,1);
|
||||
// PermissionLimits::Set($uid,$perm,1);
|
||||
|
||||
if($perm === 'view_wiki')
|
||||
\Zotlabs\Access\PermissionLimits::Set($uid, $perm, PERMS_PUBLIC);
|
||||
PermissionLimits::Set($uid, $perm, PERMS_PUBLIC);
|
||||
|
||||
if($perm === 'write_wiki')
|
||||
\Zotlabs\Access\PermissionLimits::Set($uid, $perm, PERMS_SPECIFIC);
|
||||
PermissionLimits::Set($uid, $perm, PERMS_SPECIFIC);
|
||||
|
||||
|
||||
// set autoperms here if applicable
|
||||
@@ -258,11 +262,11 @@ class PermissionRoles {
|
||||
case 'view_wiki':
|
||||
set_abconfig($uid,$ab['abook_xchan'],'my_perms',$perm,
|
||||
intval(get_abconfig($uid,$ab['abook_xchan'],'my_perms','view_pages')));
|
||||
|
||||
break;
|
||||
case 'write_wiki':
|
||||
set_abconfig($uid,$ab['abook_xchan'],'my_perms',$perm,
|
||||
intval(get_abconfig($uid,$ab['abook_xchan'],'my_perms','write_pages')));
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -313,4 +317,4 @@ class PermissionRoles {
|
||||
return $roles;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class Permissions {
|
||||
|
||||
$x = [
|
||||
'permissions' => $perms,
|
||||
'filter' => $filter
|
||||
'filter' => $filter
|
||||
];
|
||||
/**
|
||||
* @hooks permissions_list
|
||||
@@ -84,7 +84,7 @@ class Permissions {
|
||||
*/
|
||||
call_hooks('permissions_list', $x);
|
||||
|
||||
return($x['permissions']);
|
||||
return ($x['permissions']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,10 +96,10 @@ class Permissions {
|
||||
*/
|
||||
static public function BlockedAnonPerms() {
|
||||
|
||||
$res = [];
|
||||
$res = [];
|
||||
$perms = PermissionLimits::Std_limits();
|
||||
foreach($perms as $perm => $limit) {
|
||||
if($limit != PERMS_PUBLIC) {
|
||||
foreach ($perms as $perm => $limit) {
|
||||
if ($limit != PERMS_PUBLIC) {
|
||||
$res[] = $perm;
|
||||
}
|
||||
}
|
||||
@@ -111,7 +111,7 @@ class Permissions {
|
||||
*/
|
||||
call_hooks('write_perms', $x);
|
||||
|
||||
return($x['permissions']);
|
||||
return ($x['permissions']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,20 +120,20 @@ class Permissions {
|
||||
* Converts [ 0 => 'view_stream', ... ]
|
||||
* to [ 'view_stream' => 1 ] for any permissions in $arr;
|
||||
* Undeclared permissions which exist in Perms() are added and set to 0.
|
||||
*
|
||||
*
|
||||
* @param array $arr
|
||||
* @return array
|
||||
*/
|
||||
static public function FilledPerms($arr) {
|
||||
if(is_null($arr)) {
|
||||
if (is_null($arr)) {
|
||||
btlogger('FilledPerms: null');
|
||||
$arr = [];
|
||||
}
|
||||
|
||||
$everything = self::Perms();
|
||||
$ret = [];
|
||||
foreach($everything as $k => $v) {
|
||||
if(in_array($k, $arr))
|
||||
$ret = [];
|
||||
foreach ($everything as $k => $v) {
|
||||
if (in_array($k, $arr))
|
||||
$ret[$k] = 1;
|
||||
else
|
||||
$ret[$k] = 0;
|
||||
@@ -155,9 +155,9 @@ class Permissions {
|
||||
*/
|
||||
static public function OPerms($arr) {
|
||||
$ret = [];
|
||||
if($arr) {
|
||||
foreach($arr as $k => $v) {
|
||||
$ret[] = [ 'name' => $k, 'value' => $v ];
|
||||
if ($arr) {
|
||||
foreach ($arr as $k => $v) {
|
||||
$ret[] = ['name' => $k, 'value' => $v];
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
@@ -170,15 +170,16 @@ class Permissions {
|
||||
* @return boolean|array
|
||||
*/
|
||||
static public function FilledAutoperms($channel_id) {
|
||||
if(! intval(get_pconfig($channel_id,'system','autoperms')))
|
||||
if (!intval(get_pconfig($channel_id, 'system', 'autoperms')))
|
||||
return false;
|
||||
|
||||
$arr = [];
|
||||
|
||||
$r = q("select * from pconfig where uid = %d and cat = 'autoperms'",
|
||||
intval($channel_id)
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$arr[$rr['k']] = intval($rr['v']);
|
||||
}
|
||||
}
|
||||
@@ -193,11 +194,11 @@ class Permissions {
|
||||
* @return boolean true if all perms from $p1 exist also in $p2
|
||||
*/
|
||||
static public function PermsCompare($p1, $p2) {
|
||||
foreach($p1 as $k => $v) {
|
||||
if(! array_key_exists($k, $p2))
|
||||
foreach ($p1 as $k => $v) {
|
||||
if (!array_key_exists($k, $p2))
|
||||
return false;
|
||||
|
||||
if($p1[$k] != $p2[$k])
|
||||
if ($p1[$k] != $p2[$k])
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -214,18 +215,18 @@ class Permissions {
|
||||
*/
|
||||
static public function connect_perms($channel_id) {
|
||||
|
||||
$my_perms = [];
|
||||
$permcat = null;
|
||||
$my_perms = [];
|
||||
$permcat = null;
|
||||
$automatic = 0;
|
||||
|
||||
// If a default permcat exists, use that
|
||||
|
||||
$pc = ((feature_enabled($channel_id,'permcats')) ? get_pconfig($channel_id,'system','default_permcat') : 'default');
|
||||
if(! in_array($pc, [ '','default' ])) {
|
||||
$pcp = new Zlib\Permcat($channel_id);
|
||||
$pc = ((feature_enabled($channel_id, 'permcats')) ? get_pconfig($channel_id, 'system', 'default_permcat') : 'default');
|
||||
if (!in_array($pc, ['', 'default'])) {
|
||||
$pcp = new Zlib\Permcat($channel_id);
|
||||
$permcat = $pcp->fetch($pc);
|
||||
if($permcat && $permcat['perms']) {
|
||||
foreach($permcat['perms'] as $p) {
|
||||
if ($permcat && $permcat['perms']) {
|
||||
foreach ($permcat['perms'] as $p) {
|
||||
$my_perms[$p['name']] = $p['value'];
|
||||
}
|
||||
}
|
||||
@@ -235,15 +236,15 @@ class Permissions {
|
||||
// and if there was no permcat or a default permcat, set the perms
|
||||
// from the role
|
||||
|
||||
$role = get_pconfig($channel_id,'system','permissions_role');
|
||||
if($role) {
|
||||
$role = get_pconfig($channel_id, 'system', 'permissions_role');
|
||||
if ($role) {
|
||||
$xx = PermissionRoles::role_perms($role);
|
||||
if($xx['perms_auto'])
|
||||
if ($xx['perms_auto'])
|
||||
$automatic = 1;
|
||||
|
||||
if((! $my_perms) && ($xx['perms_connect'])) {
|
||||
if ((!$my_perms) && ($xx['perms_connect'])) {
|
||||
$default_perms = $xx['perms_connect'];
|
||||
$my_perms = Permissions::FilledPerms($default_perms);
|
||||
$my_perms = Permissions::FilledPerms($default_perms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,11 +252,11 @@ class Permissions {
|
||||
// it is likely a custom permissions role. First see if there are any
|
||||
// automatic permissions.
|
||||
|
||||
if(! $my_perms) {
|
||||
if (!$my_perms) {
|
||||
$m = Permissions::FilledAutoperms($channel_id);
|
||||
if($m) {
|
||||
if ($m) {
|
||||
$automatic = 1;
|
||||
$my_perms = $m;
|
||||
$my_perms = $m;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,24 +264,35 @@ class Permissions {
|
||||
// custom perms but they are not automatic. They will be stored in abconfig with
|
||||
// the channel's channel_hash (the 'self' connection).
|
||||
|
||||
if(! $my_perms) {
|
||||
if (!$my_perms) {
|
||||
$r = q("select channel_hash from channel where channel_id = %d",
|
||||
intval($channel_id)
|
||||
);
|
||||
if($r) {
|
||||
if ($r) {
|
||||
$x = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'my_perms'",
|
||||
intval($channel_id),
|
||||
dbesc($r[0]['channel_hash'])
|
||||
);
|
||||
if($x) {
|
||||
foreach($x as $xv) {
|
||||
if ($x) {
|
||||
foreach ($x as $xv) {
|
||||
$my_perms[$xv['k']] = intval($xv['v']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ( [ 'perms' => $my_perms, 'automatic' => $automatic ] );
|
||||
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,13 +2,12 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
|
||||
class Addon {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
call_hooks('daemon_addon',$argv);
|
||||
call_hooks('daemon_addon', $argv);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
|
||||
class Cache_embeds {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
36
Zotlabs/Daemon/Cache_query.php
Normal file
36
Zotlabs/Daemon/Cache_query.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Cache;
|
||||
|
||||
class Cache_query {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if(! $argc == 3)
|
||||
return;
|
||||
|
||||
$key = $argv[1];
|
||||
|
||||
$pid = get_config('procid', $key, false);
|
||||
if ($pid && (function_exists('posix_kill') ? posix_kill($pid, 0) : true)) {
|
||||
logger($key . ': procedure already run with pid ' . $pid, LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$pid = getmypid();
|
||||
set_config('procid', $key, $pid);
|
||||
|
||||
array_shift($argv);
|
||||
array_shift($argv);
|
||||
|
||||
$arr = json_decode(base64_decode($argv[0]), true);
|
||||
|
||||
$r = call_user_func_array('q', $arr);
|
||||
if($r)
|
||||
Cache::set($key, serialize($r));
|
||||
|
||||
del_config('procid', $key);
|
||||
}
|
||||
}
|
||||
@@ -2,39 +2,39 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
|
||||
require_once('include/hubloc.php');
|
||||
|
||||
class Checksites {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
logger('checksites: start');
|
||||
|
||||
if(($argc > 1) && ($argv[1]))
|
||||
|
||||
if (($argc > 1) && ($argv[1]))
|
||||
$site_id = $argv[1];
|
||||
|
||||
if($site_id)
|
||||
if ($site_id)
|
||||
$sql_options = " and site_url = '" . dbesc($argv[1]) . "' ";
|
||||
|
||||
$days = intval(get_config('system','sitecheckdays'));
|
||||
if($days < 1)
|
||||
$days = intval(get_config('system', 'sitecheckdays'));
|
||||
if ($days < 1)
|
||||
$days = 30;
|
||||
|
||||
$r = q("select * from site where site_dead = 0 and site_update < %s - INTERVAL %s and site_type = %d $sql_options ",
|
||||
db_utcnow(), db_quoteinterval($days . ' DAY'),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($days . ' DAY'),
|
||||
intval(SITE_TYPE_ZOT)
|
||||
);
|
||||
|
||||
if(! $r)
|
||||
if (!$r)
|
||||
return;
|
||||
|
||||
foreach($r as $rr) {
|
||||
if(! strcasecmp($rr['site_url'],z_root()))
|
||||
foreach ($r as $rr) {
|
||||
if (!strcasecmp($rr['site_url'], z_root()))
|
||||
continue;
|
||||
|
||||
$x = ping_site($rr['site_url']);
|
||||
if($x['success']) {
|
||||
if ($x['success']) {
|
||||
logger('checksites: ' . $rr['site_url']);
|
||||
q("update site set site_update = '%s' where site_url = '%s' ",
|
||||
dbesc(datetime_convert()),
|
||||
|
||||
58
Zotlabs/Daemon/Convo.php
Normal file
58
Zotlabs/Daemon/Convo.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\ASCollection;
|
||||
|
||||
class Convo {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
logger('convo invoked: ' . print_r($argv, true));
|
||||
|
||||
if ($argc != 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
$id = $argv[1];
|
||||
$channel_id = intval($argv[2]);
|
||||
$contact_hash = $argv[3];
|
||||
|
||||
$channel = channelx_by_n($channel_id);
|
||||
if (!$channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1",
|
||||
intval($channel_id),
|
||||
dbesc($contact_hash)
|
||||
);
|
||||
if (!$r) {
|
||||
return;
|
||||
}
|
||||
|
||||
$contact = array_shift($r);
|
||||
|
||||
$obj = new ASCollection($id, $channel);
|
||||
|
||||
$messages = $obj->get();
|
||||
|
||||
if ($messages) {
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$message = Activity::fetch($message, $channel);
|
||||
}
|
||||
// set client flag because comments will probably just be objects and not full blown activities
|
||||
// and that lets us use implied_create
|
||||
$AS = new ActivityStreams($message);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
Activity::store($channel, $contact['abook_xchan'], $AS, $item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,18 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
class Cron {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
$maxsysload = intval(get_config('system','maxloadavg'));
|
||||
if($maxsysload < 1)
|
||||
$maxsysload = intval(get_config('system', 'maxloadavg'));
|
||||
if ($maxsysload < 1)
|
||||
$maxsysload = 50;
|
||||
if(function_exists('sys_getloadavg')) {
|
||||
if (function_exists('sys_getloadavg')) {
|
||||
$load = sys_getloadavg();
|
||||
if(intval($load[0]) > $maxsysload) {
|
||||
if (intval($load[0]) > $maxsysload) {
|
||||
logger('system: load ' . $load . ' too high. Cron deferred to next scheduled run.');
|
||||
return;
|
||||
}
|
||||
@@ -19,28 +21,33 @@ class Cron {
|
||||
|
||||
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
|
||||
$lockfile = 'store/[data]/cron';
|
||||
if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
|
||||
&& (! get_config('system','override_cron_lockfile'))) {
|
||||
if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
|
||||
&& (!get_config('system', 'override_cron_lockfile'))) {
|
||||
logger("cron: Already running");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
|
||||
$x = '';
|
||||
file_put_contents($lockfile, $x);
|
||||
|
||||
logger('cron: start');
|
||||
|
||||
|
||||
// run queue delivery process in the background
|
||||
|
||||
Master::Summon(array('Queue'));
|
||||
|
||||
Master::Summon(array('Poller'));
|
||||
|
||||
// maintenance for mod sharedwithme - check for updated items and remove them
|
||||
/**
|
||||
* 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')
|
||||
);
|
||||
|
||||
require_once('include/sharedwithme.php');
|
||||
apply_updates();
|
||||
|
||||
// expire any expired mail
|
||||
|
||||
q("delete from mail where expires > '%s' and expires < %s ",
|
||||
@@ -48,19 +55,26 @@ class Cron {
|
||||
db_utcnow()
|
||||
);
|
||||
|
||||
require_once('include/account.php');
|
||||
remove_expired_registrations();
|
||||
|
||||
$interval = get_config('system', 'delivery_interval', 3);
|
||||
|
||||
// expire any expired items
|
||||
|
||||
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
|
||||
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
|
||||
and item_deleted = 0 ",
|
||||
db_utcnow()
|
||||
);
|
||||
if($r) {
|
||||
if ($r) {
|
||||
require_once('include/items.php');
|
||||
foreach($r as $rr) {
|
||||
drop_item($rr['id'],false,(($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
|
||||
if($rr['item_wall']) {
|
||||
foreach ($r as $rr) {
|
||||
drop_item($rr['id'], false, (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
|
||||
if ($rr['item_wall']) {
|
||||
// The notifier isn't normally invoked unless item_drop is interactive.
|
||||
Master::Summon( [ 'Notifier', 'drop', $rr['id'] ] );
|
||||
Master::Summon(['Notifier', 'drop', $rr['id']]);
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,9 +86,9 @@ class Cron {
|
||||
dbesc(NULL_DATE),
|
||||
db_utcnow()
|
||||
);
|
||||
if($r) {
|
||||
if ($r) {
|
||||
require_once('include/security.php');
|
||||
foreach($r as $rr) {
|
||||
foreach ($r as $rr) {
|
||||
atoken_delete($rr['atoken_id']);
|
||||
}
|
||||
}
|
||||
@@ -84,67 +98,69 @@ class Cron {
|
||||
// or dead entries.
|
||||
|
||||
$r = q("select channel_id from channel where channel_dirdate < %s - INTERVAL %s and channel_removed = 0",
|
||||
db_utcnow(),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('30 DAY')
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
Master::Summon(array('Directory',$rr['channel_id'],'force'));
|
||||
if($interval)
|
||||
@time_sleep_until(microtime(true) + (float) $interval);
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
Master::Summon(array('Directory', $rr['channel_id'], 'force'));
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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) {
|
||||
foreach($r as $rr) {
|
||||
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)) {
|
||||
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
|
||||
// couple of days to limit the query to something reasonable.
|
||||
// couple of days to limit the query to something reasonable.
|
||||
|
||||
$r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
|
||||
db_utcnow(),
|
||||
dbesc(datetime_convert('UTC','UTC','now - 2 days'))
|
||||
dbesc(datetime_convert('UTC', 'UTC', 'now - 2 days'))
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$x = q("update item set item_delayed = 0 where id = %d",
|
||||
intval($rr['id'])
|
||||
);
|
||||
if($x) {
|
||||
if ($x) {
|
||||
$z = q("select * from item where id = %d",
|
||||
intval($message_id)
|
||||
intval($rr['id'])
|
||||
);
|
||||
if($z) {
|
||||
if ($z) {
|
||||
xchan_query($z);
|
||||
$sync_item = fetch_post_tags($z);
|
||||
build_sync_packet($sync_item[0]['uid'],
|
||||
[
|
||||
'item' => [ encode_item($sync_item[0],true) ]
|
||||
Libsync::build_sync_packet($sync_item[0]['uid'],
|
||||
[
|
||||
'item' => [encode_item($sync_item[0], true)]
|
||||
]
|
||||
);
|
||||
}
|
||||
Master::Summon(array('Notifier','wall-new',$rr['id']));
|
||||
Master::Summon(array('Notifier', 'wall-new', $rr['id']));
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,43 +168,38 @@ class Cron {
|
||||
require_once('include/attach.php');
|
||||
attach_upgrade();
|
||||
|
||||
$abandon_days = intval(get_config('system','account_abandon_days'));
|
||||
if($abandon_days < 1)
|
||||
$abandon_days = 0;
|
||||
|
||||
|
||||
// once daily run birthday_updates and then expire in background
|
||||
|
||||
// FIXME: add birthday updates, both locally and for xprof for use
|
||||
// by directory servers
|
||||
|
||||
$d1 = intval(get_config('system','last_expire_day'));
|
||||
$d2 = intval(datetime_convert('UTC','UTC','now','d'));
|
||||
$d1 = intval(get_config('system', 'last_expire_day'));
|
||||
$d2 = intval(datetime_convert('UTC', 'UTC', 'now', 'd'));
|
||||
|
||||
// Allow somebody to staggger daily activities if they have more than one site on their server,
|
||||
// or if it happens at an inconvenient (busy) hour.
|
||||
|
||||
$h1 = intval(get_config('system','cron_hour'));
|
||||
$h2 = intval(datetime_convert('UTC','UTC','now','G'));
|
||||
$h1 = intval(get_config('system', 'cron_hour'));
|
||||
$h2 = intval(datetime_convert('UTC', 'UTC', 'now', 'G'));
|
||||
|
||||
|
||||
if(($d2 != $d1) && ($h1 == $h2)) {
|
||||
if (($d2 != $d1) && ($h1 == $h2)) {
|
||||
Master::Summon(array('Cron_daily'));
|
||||
}
|
||||
|
||||
// update any photos which didn't get imported properly
|
||||
// This should be rare
|
||||
|
||||
$r = q("select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = ''
|
||||
$r = q("select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = ''
|
||||
and xchan_photo_date < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('1 DAY')
|
||||
);
|
||||
if($r) {
|
||||
if ($r) {
|
||||
require_once('include/photo/photo_driver.php');
|
||||
foreach($r as $rr) {
|
||||
$photos = import_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']);
|
||||
$x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
|
||||
foreach ($r as $rr) {
|
||||
$photos = import_xchan_photo($rr['xchan_photo_l'], $rr['xchan_hash'], false, true);
|
||||
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]),
|
||||
dbesc($photos[1]),
|
||||
@@ -202,33 +213,30 @@ class Cron {
|
||||
|
||||
// pull in some public posts
|
||||
|
||||
$disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
|
||||
if(! $disable_discover_tab)
|
||||
/* $disable_discover_tab = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false;
|
||||
if (!$disable_discover_tab)
|
||||
Master::Summon(array('Externals'));
|
||||
*/
|
||||
|
||||
$generation = 0;
|
||||
$restart = false;
|
||||
|
||||
$restart = false;
|
||||
|
||||
if(($argc > 1) && ($argv[1] == 'restart')) {
|
||||
$restart = true;
|
||||
if (($argc > 1) && ($argv[1] == 'restart')) {
|
||||
$restart = true;
|
||||
$generation = intval($argv[2]);
|
||||
if(! $generation)
|
||||
killme();
|
||||
if (!$generation)
|
||||
return;
|
||||
}
|
||||
|
||||
reload_plugins();
|
||||
|
||||
$d = datetime_convert();
|
||||
|
||||
// TODO check to see if there are any cronhooks before wasting a process
|
||||
|
||||
if(! $restart)
|
||||
if (!$restart)
|
||||
Master::Summon(array('Cronhooks'));
|
||||
|
||||
set_config('system','lastcron',datetime_convert());
|
||||
set_config('system', 'lastcron', datetime_convert());
|
||||
|
||||
//All done - clear the lockfile
|
||||
//All done - clear the lockfile
|
||||
@unlink($lockfile);
|
||||
|
||||
return;
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
|
||||
class Cron_daily {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
logger('cron_daily: start');
|
||||
|
||||
@@ -13,15 +15,12 @@ class Cron_daily {
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
require_once('include/dir_fns.php');
|
||||
check_upstream_directory();
|
||||
|
||||
Libzotdir::check_upstream_directory();
|
||||
|
||||
// Fire off the Cron_weekly process if it's the correct day.
|
||||
|
||||
$d3 = intval(datetime_convert('UTC','UTC','now','N'));
|
||||
if($d3 == 7) {
|
||||
|
||||
$d3 = intval(datetime_convert('UTC', 'UTC', 'now', 'N'));
|
||||
if ($d3 == 7) {
|
||||
Master::Summon(array('Cron_weekly'));
|
||||
}
|
||||
|
||||
@@ -44,6 +43,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');
|
||||
@@ -56,8 +66,8 @@ class Cron_daily {
|
||||
|
||||
// expire old delivery reports
|
||||
|
||||
$keep_reports = intval(get_config('system','expire_delivery_reports'));
|
||||
if($keep_reports === 0)
|
||||
$keep_reports = intval(get_config('system', 'expire_delivery_reports'));
|
||||
if ($keep_reports === 0)
|
||||
$keep_reports = 10;
|
||||
|
||||
q("delete from dreport where dreport_time < %s - INTERVAL %s",
|
||||
@@ -69,27 +79,26 @@ class Cron_daily {
|
||||
downgrade_accounts();
|
||||
|
||||
// If this is a directory server, request a sync with an upstream
|
||||
// directory at least once a day, up to once every poll interval.
|
||||
// directory at least once a day, up to once every poll interval.
|
||||
// Pull remote changes and push local changes.
|
||||
// potential issue: how do we keep from creating an endless update loop?
|
||||
// potential issue: how do we keep from creating an endless update loop?
|
||||
|
||||
$dirmode = get_config('system','directory_mode');
|
||||
$dirmode = get_config('system', 'directory_mode');
|
||||
|
||||
if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
require_once('include/dir_fns.php');
|
||||
sync_directories($dirmode);
|
||||
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
Libzotdir::sync_directories($dirmode);
|
||||
}
|
||||
|
||||
|
||||
Master::Summon(array('Expire'));
|
||||
Master::Summon(array('Cli_suggest'));
|
||||
|
||||
remove_obsolete_hublocs();
|
||||
z6_discover();
|
||||
remove_duplicate_singleton_hublocs();
|
||||
|
||||
call_hooks('cron_daily',datetime_convert());
|
||||
$date = datetime_convert();
|
||||
call_hooks('cron_daily', $date);
|
||||
|
||||
set_config('system','last_expire_day',intval(datetime_convert('UTC','UTC','now','d')));
|
||||
set_config('system', 'last_expire_day', intval(datetime_convert('UTC', 'UTC', 'now', 'd')));
|
||||
|
||||
/**
|
||||
* End Cron Daily
|
||||
|
||||
@@ -4,21 +4,22 @@ namespace Zotlabs\Daemon;
|
||||
|
||||
class Cron_weekly {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
/**
|
||||
* Cron Weekly
|
||||
*
|
||||
*
|
||||
* Actions in the following block are executed once per day only on Sunday (once per week).
|
||||
*
|
||||
*/
|
||||
|
||||
call_hooks('cron_weekly',datetime_convert());
|
||||
$date = datetime_convert();
|
||||
call_hooks('cron_weekly', $date);
|
||||
|
||||
z_check_cert();
|
||||
|
||||
prune_hub_reinstalls();
|
||||
|
||||
|
||||
mark_orphan_hubsxchans();
|
||||
|
||||
// Find channels that were removed in the last three weeks, but
|
||||
@@ -31,8 +32,8 @@ class Cron_weekly {
|
||||
db_utcnow(), db_quoteinterval('21 DAY'),
|
||||
db_utcnow(), db_quoteinterval('10 DAY')
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rv) {
|
||||
if ($r) {
|
||||
foreach ($r as $rv) {
|
||||
channel_remove_final($rv['channel_id']);
|
||||
}
|
||||
}
|
||||
@@ -43,14 +44,14 @@ class Cron_weekly {
|
||||
db_utcnow(), db_quoteinterval('14 DAY')
|
||||
);
|
||||
|
||||
$dirmode = intval(get_config('system','directory_mode'));
|
||||
if($dirmode === DIRECTORY_MODE_SECONDARY || $dirmode === DIRECTORY_MODE_PRIMARY) {
|
||||
logger('regdir: ' . print_r(z_fetch_url(get_directory_primary() . '/regdir?f=&url=' . urlencode(z_root()) . '&realm=' . urlencode(get_directory_realm())),true));
|
||||
$dirmode = intval(get_config('system', 'directory_mode'));
|
||||
if ($dirmode === DIRECTORY_MODE_SECONDARY || $dirmode === DIRECTORY_MODE_PRIMARY) {
|
||||
logger('regdir: ' . print_r(z_fetch_url(get_directory_primary() . '/regdir?f=&url=' . urlencode(z_root()) . '&realm=' . urlencode(get_directory_realm())), true));
|
||||
}
|
||||
|
||||
// Check for dead sites
|
||||
Master::Summon(array('Checksites'));
|
||||
|
||||
|
||||
// update searchable doc indexes
|
||||
Master::Summon(array('Importdoc'));
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use App;
|
||||
|
||||
// generate a curl compatible cookie file with an authenticated session for the given channel_id.
|
||||
// If this file is then used with curl and the destination url is sent through zid() or manually
|
||||
// manipulated to add a zid, it should allow curl to provide zot magic-auth across domains.
|
||||
@@ -10,15 +12,15 @@ namespace Zotlabs\Daemon;
|
||||
|
||||
class CurlAuth {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if($argc != 2)
|
||||
killme();
|
||||
if ($argc != 2)
|
||||
return;
|
||||
|
||||
\App::$session->start();
|
||||
App::$session->start();
|
||||
|
||||
$_SESSION['authenticated'] = 1;
|
||||
$_SESSION['uid'] = $argv[1];
|
||||
$_SESSION['uid'] = $argv[1];
|
||||
|
||||
$x = session_id();
|
||||
|
||||
@@ -29,14 +31,14 @@ class CurlAuth {
|
||||
|
||||
$output = '';
|
||||
|
||||
if($e) {
|
||||
if ($e) {
|
||||
$lines = file($f);
|
||||
if($lines) {
|
||||
foreach($lines as $line) {
|
||||
if(strlen($line) > 0 && $line[0] != '#' && substr_count($line, "\t") == 6) {
|
||||
if ($lines) {
|
||||
foreach ($lines as $line) {
|
||||
if (strlen($line) > 0 && $line[0] != '#' && substr_count($line, "\t") == 6) {
|
||||
$tokens = explode("\t", $line);
|
||||
$tokens = array_map('trim', $tokens);
|
||||
if($tokens[4] > time()) {
|
||||
if ($tokens[4] > time()) {
|
||||
$output .= $line . "\n";
|
||||
}
|
||||
}
|
||||
@@ -46,10 +48,10 @@ class CurlAuth {
|
||||
}
|
||||
}
|
||||
$t = time() + (24 * 3600);
|
||||
file_put_contents($f, $output . 'HttpOnly_' . \App::get_hostname() . "\tFALSE\t/\tTRUE\t$t\tPHPSESSID\t" . $x, (($e) ? FILE_APPEND : 0));
|
||||
file_put_contents($f, $output . 'HttpOnly_' . App::get_hostname() . "\tFALSE\t/\tTRUE\t$t\tPHPSESSID\t" . $x, (($e) ? FILE_APPEND : 0));
|
||||
|
||||
file_put_contents($c,$x);
|
||||
file_put_contents($c, $x);
|
||||
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,92 +2,32 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\DReport;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/queue_fn.php');
|
||||
|
||||
use Zotlabs\Lib\Queue;
|
||||
|
||||
class Deliver {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
if($argc < 2)
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if ($argc < 2)
|
||||
return;
|
||||
|
||||
logger('deliver: invoked: ' . print_r($argv,true), LOGGER_DATA);
|
||||
logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA);
|
||||
|
||||
for($x = 1; $x < $argc; $x ++) {
|
||||
for ($x = 1; $x < $argc; $x++) {
|
||||
|
||||
if(! $argv[$x])
|
||||
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);
|
||||
|
||||
if ($r) {
|
||||
Queue::deliver($r[0], true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,21 +2,18 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
|
||||
class Deliver_hooks {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if($argc < 2)
|
||||
if ($argc < 2)
|
||||
return;
|
||||
|
||||
|
||||
$r = q("select * from item where id = '%d'",
|
||||
intval($argv[1])
|
||||
);
|
||||
if($r)
|
||||
call_hooks('notifier_normal',$r[0]);
|
||||
if ($r)
|
||||
call_hooks('notifier_normal', $r[0]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,47 +2,46 @@
|
||||
|
||||
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 {
|
||||
|
||||
static public function run($argc,$argv){
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if($argc < 2)
|
||||
if ($argc < 2)
|
||||
return;
|
||||
|
||||
$force = false;
|
||||
$force = false;
|
||||
$pushall = true;
|
||||
|
||||
if($argc > 2) {
|
||||
if($argv[2] === 'force')
|
||||
if ($argc > 2) {
|
||||
if ($argv[2] === 'force')
|
||||
$force = true;
|
||||
if($argv[2] === 'nopush')
|
||||
if ($argv[2] === 'nopush')
|
||||
$pushall = false;
|
||||
}
|
||||
}
|
||||
|
||||
logger('directory update', LOGGER_DEBUG);
|
||||
|
||||
$dirmode = get_config('system','directory_mode');
|
||||
if($dirmode === false)
|
||||
$dirmode = get_config('system', 'directory_mode');
|
||||
if ($dirmode === false)
|
||||
$dirmode = DIRECTORY_MODE_NORMAL;
|
||||
|
||||
$x = q("select * from channel where channel_id = %d limit 1",
|
||||
intval($argv[1])
|
||||
);
|
||||
if(! $x)
|
||||
if (!$x)
|
||||
return;
|
||||
|
||||
$channel = $x[0];
|
||||
|
||||
if($dirmode != DIRECTORY_MODE_NORMAL) {
|
||||
if ($dirmode != DIRECTORY_MODE_NORMAL) {
|
||||
|
||||
// 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()),
|
||||
@@ -50,33 +49,34 @@ class Directory {
|
||||
);
|
||||
|
||||
// Now update all the connections
|
||||
if($pushall)
|
||||
Master::Summon(array('Notifier','refresh_all',$channel['channel_id']));
|
||||
if ($pushall)
|
||||
Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id']));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
if(! $z['success']) {
|
||||
if (!$z['success']) {
|
||||
|
||||
/** @FIXME we aren't updating channel_dirdate if we have to queue
|
||||
* the directory packet. That means we'll try again on the next poll run.
|
||||
*/
|
||||
|
||||
$hash = random_string();
|
||||
$hash = new_uuid();
|
||||
|
||||
queue_insert(array(
|
||||
Queue::insert(array(
|
||||
'hash' => $hash,
|
||||
'account_id' => $channel['channel_account_id'],
|
||||
'channel_id' => $channel['channel_id'],
|
||||
@@ -93,8 +93,8 @@ class Directory {
|
||||
}
|
||||
|
||||
// Now update all the connections
|
||||
if($pushall)
|
||||
Master::Summon(array('Notifier','refresh_all',$channel['channel_id']));
|
||||
if ($pushall)
|
||||
Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id']));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,28 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/items.php');
|
||||
|
||||
class Expire {
|
||||
|
||||
static public function run($argc,$argv){
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
cli_startup();
|
||||
|
||||
$pid = get_config('procid', 'expire', false);
|
||||
if ($pid && (function_exists('posix_kill') ? posix_kill($pid, 0) : true)) {
|
||||
logger('procedure already run with pid ' . $pid, LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$pid = getmypid();
|
||||
set_config('procid', 'expire', $pid);
|
||||
|
||||
// perform final cleanup on previously delete items
|
||||
|
||||
$r = q("select id from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
|
||||
db_utcnow(), db_quoteinterval('10 DAY')
|
||||
db_utcnow(),
|
||||
db_quoteinterval('10 DAY')
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
@@ -23,23 +34,22 @@ class Expire {
|
||||
// physically remove anything that has been deleted for more than two months
|
||||
/** @FIXME - this is a wretchedly inefficient query */
|
||||
|
||||
$r = q("delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s",
|
||||
db_utcnow(), db_quoteinterval('36 DAY')
|
||||
q("delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval('36 DAY')
|
||||
);
|
||||
|
||||
/** @FIXME make this optional as it could have a performance impact on large sites */
|
||||
|
||||
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'));
|
||||
$site_expire = intval(get_config('system', 'default_expire_days'));
|
||||
$commented_days = intval(get_config('system', 'active_expire_days'));
|
||||
|
||||
logger('site_expire: ' . $site_expire);
|
||||
|
||||
$r = q("SELECT channel_id, channel_system, channel_address, channel_expire_days from channel where true");
|
||||
$r = dbq("SELECT channel_id, channel_system, channel_address, channel_expire_days from channel where true");
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
@@ -55,11 +65,12 @@ class Expire {
|
||||
$channel_expire = $service_class_expire;
|
||||
else
|
||||
$channel_expire = $site_expire;
|
||||
|
||||
|
||||
if (intval($channel_expire) && (intval($channel_expire) < intval($rr['channel_expire_days'])) ||
|
||||
intval($rr['channel_expire_days'] == 0)) {
|
||||
$expire_days = $channel_expire;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$expire_days = $rr['channel_expire_days'];
|
||||
}
|
||||
|
||||
@@ -84,11 +95,13 @@ class Expire {
|
||||
}
|
||||
|
||||
logger('Expire: sys interval: ' . $expire_days, LOGGER_DEBUG);
|
||||
|
||||
|
||||
if ($expire_days)
|
||||
item_expire($x['channel_id'], $expire_days, $commented_days);
|
||||
|
||||
logger('Expire: sys: done', LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
del_config('procid', 'expire');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,97 +2,180 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\ASCollection;
|
||||
|
||||
require_once('include/channel.php');
|
||||
|
||||
|
||||
class Externals {
|
||||
|
||||
static public function run($argc,$argv){
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
$total = 0;
|
||||
logger('externals: start');
|
||||
|
||||
$importer = get_sys_channel();
|
||||
$total = 0;
|
||||
$attempts = 0;
|
||||
|
||||
logger('externals: startup', LOGGER_DEBUG);
|
||||
|
||||
// pull in some public posts
|
||||
|
||||
while ($total == 0 && $attempts < 3) {
|
||||
$arr = ['url' => ''];
|
||||
call_hooks('externals_url_select', $arr);
|
||||
|
||||
while($total == 0 && $attempts < 3) {
|
||||
$arr = array('url' => '');
|
||||
call_hooks('externals_url_select',$arr);
|
||||
|
||||
if($arr['url']) {
|
||||
if ($arr['url']) {
|
||||
$url = $arr['url'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$randfunc = db_getfunc('RAND');
|
||||
|
||||
// fixme this query does not deal with directory realms.
|
||||
// fixme this query does not deal with directory realms.
|
||||
|
||||
$r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d and site_dead = 0 order by $randfunc limit 1",
|
||||
$r = q("select site_url, site_pull from site where site_url != '%s'
|
||||
and site_flags != %d and site_type = %d
|
||||
and site_dead = 0 and site_project like '%s' and site_version > '5.3.1' order by $randfunc limit 1",
|
||||
dbesc(z_root()),
|
||||
intval(DIRECTORY_MODE_STANDALONE),
|
||||
intval(SITE_TYPE_ZOT)
|
||||
intval(SITE_TYPE_ZOT),
|
||||
dbesc('hubzilla%')
|
||||
);
|
||||
if($r)
|
||||
if ($r)
|
||||
$url = $r[0]['site_url'];
|
||||
}
|
||||
|
||||
$blacklisted = false;
|
||||
|
||||
if(! check_siteallowed($url)) {
|
||||
if (!check_siteallowed($url)) {
|
||||
logger('blacklisted site: ' . $url);
|
||||
$blacklisted = true;
|
||||
}
|
||||
|
||||
$attempts ++;
|
||||
$attempts++;
|
||||
|
||||
// make sure we can eventually break out if somebody blacklists all known sites
|
||||
|
||||
if($blacklisted) {
|
||||
if($attempts > 20)
|
||||
if ($blacklisted) {
|
||||
if ($attempts > 20)
|
||||
break;
|
||||
$attempts --;
|
||||
$attempts--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if($url) {
|
||||
if($r[0]['site_pull'] > NULL_DATE)
|
||||
$mindate = urlencode(datetime_convert('','',$r[0]['site_pull'] . ' - 1 day'));
|
||||
else {
|
||||
$days = get_config('externals','since_days');
|
||||
if($days === false)
|
||||
$days = 15;
|
||||
$mindate = urlencode(datetime_convert('','','now - ' . intval($days) . ' days'));
|
||||
}
|
||||
if ($url) {
|
||||
|
||||
$feedurl = $url . '/zotfeed?f=&mindate=' . $mindate;
|
||||
$max = intval(get_config('system', 'max_imported_posts', 30));
|
||||
if (intval($max)) {
|
||||
logger('externals: fetching outbox');
|
||||
|
||||
logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG);
|
||||
$feed_url = $url . '/zotfeed';
|
||||
$obj = new ASCollection($feed_url, $importer, 0, $max);
|
||||
$messages = $obj->get();
|
||||
|
||||
$x = z_fetch_url($feedurl);
|
||||
if(($x) && ($x['success'])) {
|
||||
|
||||
q("update site set site_pull = '%s' where site_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($url)
|
||||
);
|
||||
|
||||
$j = json_decode($x['body'],true);
|
||||
if($j['success'] && $j['messages']) {
|
||||
$sys = get_sys_channel();
|
||||
foreach($j['messages'] as $message) {
|
||||
// on these posts, clear any route info.
|
||||
$message['route'] = '';
|
||||
$results = process_delivery(array('hash' => 'undefined'), get_item_elements($message),
|
||||
array(array('hash' => $sys['xchan_hash'])), false, true);
|
||||
$total ++;
|
||||
if ($messages) {
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$message = Activity::fetch($message, $importer);
|
||||
}
|
||||
$AS = new ActivityStreams($message);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
Activity::store($importer, $importer['xchan_hash'], $AS, $item, true);
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG);
|
||||
}
|
||||
logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
/* $total = 0;
|
||||
$attempts = 0;
|
||||
|
||||
logger('externals: startup', LOGGER_DEBUG);
|
||||
|
||||
// pull in some public posts
|
||||
|
||||
while ($total == 0 && $attempts < 3) {
|
||||
$arr = ['url' => ''];
|
||||
call_hooks('externals_url_select', $arr);
|
||||
|
||||
if ($arr['url']) {
|
||||
$url = $arr['url'];
|
||||
}
|
||||
else {
|
||||
$randfunc = db_getfunc('RAND');
|
||||
|
||||
// fixme this query does not deal with directory realms.
|
||||
|
||||
$r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d and site_dead = 0 order by $randfunc limit 1",
|
||||
dbesc(z_root()),
|
||||
intval(DIRECTORY_MODE_STANDALONE),
|
||||
intval(SITE_TYPE_ZOT)
|
||||
);
|
||||
if ($r)
|
||||
$url = $r[0]['site_url'];
|
||||
}
|
||||
|
||||
$blacklisted = false;
|
||||
|
||||
if (!check_siteallowed($url)) {
|
||||
logger('blacklisted site: ' . $url);
|
||||
$blacklisted = true;
|
||||
}
|
||||
|
||||
$attempts++;
|
||||
|
||||
// make sure we can eventually break out if somebody blacklists all known sites
|
||||
|
||||
if ($blacklisted) {
|
||||
if ($attempts > 20)
|
||||
break;
|
||||
$attempts--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($url) {
|
||||
if ($r[0]['site_pull'] > NULL_DATE)
|
||||
$mindate = urlencode(datetime_convert('', '', $r[0]['site_pull'] . ' - 1 day'));
|
||||
else {
|
||||
$days = get_config('externals', 'since_days');
|
||||
if ($days === false)
|
||||
$days = 15;
|
||||
$mindate = urlencode(datetime_convert('', '', 'now - ' . intval($days) . ' days'));
|
||||
}
|
||||
|
||||
$feedurl = $url . '/zotfeed?f=&mindate=' . $mindate;
|
||||
|
||||
logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG);
|
||||
|
||||
$x = z_fetch_url($feedurl);
|
||||
if (($x) && ($x['success'])) {
|
||||
|
||||
q("update site set site_pull = '%s' where site_url = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($url)
|
||||
);
|
||||
|
||||
$j = json_decode($x['body'], true);
|
||||
if ($j['success'] && $j['messages']) {
|
||||
$sys = get_sys_channel();
|
||||
foreach ($j['messages'] as $message) {
|
||||
// on these posts, clear any route info.
|
||||
$message['route'] = '';
|
||||
process_delivery(['hash' => 'undefined'], get_item_elements($message),
|
||||
[['hash' => $sys['xchan_hash']]], false, true);
|
||||
$total++;
|
||||
}
|
||||
logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,32 +2,38 @@
|
||||
|
||||
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
|
||||
|
||||
class Gprobe {
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if($argc != 2)
|
||||
if ($argc != 2)
|
||||
return;
|
||||
|
||||
$url = hex2bin($argv[1]);
|
||||
|
||||
if(! strpos($url,'@'))
|
||||
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);
|
||||
if (!$r) {
|
||||
$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'])) {
|
||||
Libzot::import_xchan($zf['data']);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
14
Zotlabs/Daemon/Importdoc.php
Executable file → Normal file
14
Zotlabs/Daemon/Importdoc.php
Executable file → Normal file
@@ -5,7 +5,7 @@ namespace Zotlabs\Daemon;
|
||||
|
||||
class Importdoc {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
require_once('include/help.php');
|
||||
|
||||
@@ -16,20 +16,20 @@ class Importdoc {
|
||||
static public function update_docs_dir($s) {
|
||||
$f = basename($s);
|
||||
$d = dirname($s);
|
||||
if($s === 'doc/html')
|
||||
if ($s === 'doc/html')
|
||||
return;
|
||||
$files = glob("$d/$f");
|
||||
if($files) {
|
||||
foreach($files as $fi) {
|
||||
if($fi === 'doc/html') {
|
||||
if ($files) {
|
||||
foreach ($files as $fi) {
|
||||
if ($fi === 'doc/html') {
|
||||
continue;
|
||||
}
|
||||
if(is_dir($fi)) {
|
||||
if (is_dir($fi)) {
|
||||
self::update_docs_dir("$fi/*");
|
||||
}
|
||||
else {
|
||||
// don't update media content
|
||||
if(strpos(z_mime_content_type($fi),'text') === 0) {
|
||||
if (strpos(z_mime_content_type($fi), 'text') === 0) {
|
||||
store_doc_file($fi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,24 +2,25 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
class Importfile {
|
||||
|
||||
static public function run($argc,$argv){
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
logger('Importfile: ' . print_r($argv,true));
|
||||
logger('Importfile: ' . print_r($argv, true));
|
||||
|
||||
if($argc < 3)
|
||||
if ($argc < 3)
|
||||
return;
|
||||
|
||||
$channel = channelx_by_n($argv[1]);
|
||||
if(! $channel)
|
||||
if (!$channel)
|
||||
return;
|
||||
|
||||
$srcfile = $argv[2];
|
||||
$folder = (($argc > 3) ? $argv[3] : '');
|
||||
$dstname = (($argc > 4) ? $argv[4] : '');
|
||||
|
||||
$hash = random_string();
|
||||
$hash = random_string();
|
||||
|
||||
$arr = [
|
||||
'src' => $srcfile,
|
||||
@@ -33,15 +34,15 @@ class Importfile {
|
||||
'replace' => true
|
||||
];
|
||||
|
||||
if($folder)
|
||||
if ($folder)
|
||||
$arr['folder'] = $folder;
|
||||
|
||||
attach_store($channel,$channel['channel_hash'],'import',$arr);
|
||||
attach_store($channel, $channel['channel_hash'], 'import', $arr);
|
||||
|
||||
$sync = attach_export_data($channel, $hash);
|
||||
if ($sync)
|
||||
Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
|
||||
|
||||
$sync = attach_export_data($channel,$hash);
|
||||
if($sync)
|
||||
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,42 +2,57 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
if(array_search( __file__ , get_included_files()) === 0) {
|
||||
if (array_search(__file__, get_included_files()) === 0) {
|
||||
require_once('include/cli_startup.php');
|
||||
array_shift($argv);
|
||||
$argc = count($argv);
|
||||
|
||||
if($argc)
|
||||
Master::Release($argc,$argv);
|
||||
killme();
|
||||
if ($argc)
|
||||
Master::Release($argc, $argv);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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) || ($argc < 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) {
|
||||
static public function Release($argc, $argv) {
|
||||
cli_startup();
|
||||
|
||||
$hookinfo = [
|
||||
'argv'=>$argv
|
||||
'argv' => $argv
|
||||
];
|
||||
|
||||
call_hooks ('daemon_master_release',$hookinfo);
|
||||
call_hooks('daemon_master_release', $hookinfo);
|
||||
|
||||
$argv = $hookinfo['argv'];
|
||||
$argc = count($argv);
|
||||
|
||||
if ((!is_array($argv) || (count($argv) < 1))) {
|
||||
if ((!is_array($argv) || ($argc < 1))) {
|
||||
logger("Release handled by hook.", LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
logger('Master: release: ' . json_encode($argv), LOGGER_ALL,LOG_DEBUG);
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$cls::run($argc,$argv);
|
||||
logger('Master: release: ' . json_encode($argv), LOGGER_ALL, LOG_DEBUG);
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$cls::run($argc, $argv);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,31 +2,31 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/dir_fns.php');
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
|
||||
class Onedirsync {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
logger('onedirsync: start ' . intval($argv[1]));
|
||||
|
||||
if(($argc > 1) && (intval($argv[1])))
|
||||
|
||||
if (($argc > 1) && (intval($argv[1])))
|
||||
$update_id = intval($argv[1]);
|
||||
|
||||
if(! $update_id) {
|
||||
if (!$update_id) {
|
||||
logger('onedirsync: no update');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$r = q("select * from updates where ud_id = %d limit 1",
|
||||
intval($update_id)
|
||||
);
|
||||
|
||||
if(! $r)
|
||||
if (!$r)
|
||||
return;
|
||||
if(($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (! $r[0]['ud_addr']))
|
||||
|
||||
if (($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (!$r[0]['ud_addr']))
|
||||
return;
|
||||
|
||||
// Have we probed this channel more recently than the other directory server
|
||||
@@ -38,8 +38,8 @@ class Onedirsync {
|
||||
dbesc($r[0]['ud_date']),
|
||||
intval(UPDATE_FLAGS_UPDATED)
|
||||
);
|
||||
if($x) {
|
||||
$y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'",
|
||||
if ($x) {
|
||||
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'",
|
||||
intval(UPDATE_FLAGS_UPDATED),
|
||||
dbesc($r[0]['ud_addr']),
|
||||
intval(UPDATE_FLAGS_UPDATED),
|
||||
@@ -50,26 +50,28 @@ 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",
|
||||
dbesc($r[0]['ud_addr'])
|
||||
$h = q("select * from hubloc where hubloc_addr = '%s'",
|
||||
dbesc($r[0]['ud_addr']),
|
||||
);
|
||||
if(($h) && ($h[0]['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),
|
||||
|
||||
$h = Libzot::zot_record_preferred($h);
|
||||
|
||||
if (($h) && (($h['hubloc_status'] & HUBLOC_OFFLINE) || $h['hubloc_deleted'] || $h['hubloc_error'])) {
|
||||
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ",
|
||||
intval(UPDATE_FLAGS_DELETED),
|
||||
dbesc($r[0]['ud_addr']),
|
||||
intval(UPDATE_FLAGS_UPDATED)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 && $h['hubloc_network'] !== 'zot6')
|
||||
return;
|
||||
|
||||
update_directory_entry($r[0]);
|
||||
Libzotdir::update_directory_entry($r[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,84 +2,91 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/socgraph.php');
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\ASCollection;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/socgraph.php');
|
||||
require_once('include/feedutils.php');
|
||||
|
||||
class Onepoll {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
logger('onepoll: start');
|
||||
|
||||
if(($argc > 1) && (intval($argv[1])))
|
||||
|
||||
if (($argc > 1) && (intval($argv[1])))
|
||||
$contact_id = intval($argv[1]);
|
||||
|
||||
if(! $contact_id) {
|
||||
if (!$contact_id) {
|
||||
logger('onepoll: no contact');
|
||||
return;
|
||||
}
|
||||
|
||||
$d = datetime_convert();
|
||||
$sql_extra = '';
|
||||
$allow_feeds = get_config('system', 'feed_contacts');
|
||||
if(!$allow_feeds) {
|
||||
$sql_extra = ' and abook_feed = 0 ';
|
||||
}
|
||||
|
||||
$contacts = q("SELECT abook.*, xchan.*, account.*
|
||||
FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan
|
||||
where abook_id = %d
|
||||
FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan
|
||||
where abook_id = %d $sql_extra
|
||||
and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0
|
||||
AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1",
|
||||
intval($contact_id),
|
||||
intval(ACCOUNT_OK),
|
||||
intval(ACCOUNT_UNVERIFIED)
|
||||
);
|
||||
);
|
||||
|
||||
if(! $contacts) {
|
||||
if (!$contacts) {
|
||||
logger('onepoll: abook_id not found: ' . $contact_id);
|
||||
return;
|
||||
}
|
||||
|
||||
$contact = $contacts[0];
|
||||
|
||||
$t = $contact['abook_updated'];
|
||||
|
||||
$contact = $contacts[0];
|
||||
$importer_uid = $contact['abook_channel'];
|
||||
|
||||
|
||||
$r = q("SELECT * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
|
||||
intval($importer_uid)
|
||||
);
|
||||
|
||||
if(! $r)
|
||||
if (!$r)
|
||||
return;
|
||||
|
||||
$importer = $r[0];
|
||||
|
||||
logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
|
||||
|
||||
$last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE))
|
||||
? datetime_convert('UTC','UTC','now - 7 days')
|
||||
: datetime_convert('UTC','UTC',$contact['abook_updated'] . ' - 2 days')
|
||||
$last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE))
|
||||
? datetime_convert('UTC', 'UTC', 'now - 7 days')
|
||||
: datetime_convert('UTC', 'UTC', $contact['abook_updated'] . ' - 2 days')
|
||||
);
|
||||
|
||||
if($contact['xchan_network'] === 'rss') {
|
||||
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;
|
||||
}
|
||||
|
||||
if(! in_array($contact['xchan_network'],['zot','zot6']))
|
||||
|
||||
if ($contact['xchan_network'] !== 'zot6')
|
||||
return;
|
||||
|
||||
// update permissions
|
||||
|
||||
$x = zot_refresh($contact,$importer);
|
||||
$x = Libzot::refresh($contact, $importer);
|
||||
|
||||
$responded = false;
|
||||
$updated = datetime_convert();
|
||||
$connected = datetime_convert();
|
||||
if(! $x) {
|
||||
if (!$x) {
|
||||
// mark for death by not updating abook_connected, this is caught in include/poller.php
|
||||
q("update abook set abook_updated = '%s' where abook_id = %d",
|
||||
dbesc($updated),
|
||||
@@ -95,83 +102,69 @@ class Onepoll {
|
||||
$responded = true;
|
||||
}
|
||||
|
||||
if(! $responded)
|
||||
if (!$responded)
|
||||
return;
|
||||
|
||||
if($contact['xchan_connurl']) {
|
||||
$fetch_feed = true;
|
||||
$x = null;
|
||||
$fetch_feed = true;
|
||||
|
||||
// They haven't given us permission to see their stream
|
||||
// They haven't given us permission to see their stream
|
||||
$can_view_stream = intval(get_abconfig($importer_uid, $contact['abook_xchan'], 'their_perms', 'view_stream'));
|
||||
|
||||
$can_view_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'their_perms','view_stream'));
|
||||
if (!$can_view_stream) {
|
||||
$fetch_feed = false;
|
||||
}
|
||||
|
||||
if(! $can_view_stream)
|
||||
$fetch_feed = false;
|
||||
// we haven't given them permission to send us their stream
|
||||
$can_send_stream = intval(get_abconfig($importer_uid, $contact['abook_xchan'], 'my_perms', 'send_stream'));
|
||||
|
||||
// we haven't given them permission to send us their stream
|
||||
if (!$can_send_stream) {
|
||||
$fetch_feed = false;
|
||||
}
|
||||
|
||||
$can_send_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'my_perms','send_stream'));
|
||||
|
||||
if(! $can_send_stream)
|
||||
$fetch_feed = false;
|
||||
if ($fetch_feed) {
|
||||
|
||||
if($fetch_feed) {
|
||||
$max = intval(get_config('system', 'max_imported_posts', 30));
|
||||
|
||||
if(strpos($contact['xchan_connurl'],z_root()) === 0) {
|
||||
// local channel - save a network fetch
|
||||
$c = channelx_by_hash($contact['xchan_hash']);
|
||||
if($c) {
|
||||
$x = [
|
||||
'success' => true,
|
||||
'body' => json_encode( [
|
||||
'success' => true,
|
||||
'messages' => zot_feed($c['channel_id'], $importer['xchan_hash'], [ 'mindate' => $last_update ])
|
||||
])
|
||||
];
|
||||
}
|
||||
if (intval($max)) {
|
||||
$cl = get_xconfig($contact['abook_xchan'], 'activitypub', 'collections');
|
||||
|
||||
if (is_array($cl) && array_key_exists('outbox', $cl)) {
|
||||
$url = $cl['outbox'];
|
||||
}
|
||||
else {
|
||||
// remote fetch
|
||||
|
||||
$feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']);
|
||||
$feedurl .= '?f=&mindate=' . urlencode($last_update) . '&zid=' . $importer['channel_address'] . '@' . \App::get_hostname();
|
||||
$recurse = 0;
|
||||
$x = z_fetch_url($feedurl, false, $recurse, [ 'session' => true ]);
|
||||
$url = str_replace('/poco/', '/zotfeed/', $contact['xchan_connurl']);
|
||||
}
|
||||
|
||||
logger('feed_update: ' . print_r($x,true), LOGGER_DATA);
|
||||
}
|
||||
|
||||
if(($x) && ($x['success'])) {
|
||||
$total = 0;
|
||||
logger('onepoll: feed update ' . $contact['xchan_name'] . ' ' . $feedurl);
|
||||
|
||||
$j = json_decode($x['body'],true);
|
||||
if($j['success'] && $j['messages']) {
|
||||
foreach($j['messages'] as $message) {
|
||||
$results = process_delivery(array('hash' => $contact['xchan_hash']), get_item_elements($message),
|
||||
array(array('hash' => $importer['xchan_hash'])), false);
|
||||
logger('onepoll: feed_update: process_delivery: ' . print_r($results,true), LOGGER_DATA);
|
||||
$total ++;
|
||||
if ($url) {
|
||||
logger('fetching outbox');
|
||||
$url = $url . '?date_begin=' . urlencode($last_update);
|
||||
$obj = new ASCollection($url, $importer, 0, $max);
|
||||
$messages = $obj->get();
|
||||
if ($messages) {
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$message = Activity::fetch($message, $importer);
|
||||
}
|
||||
$AS = new ActivityStreams($message);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
Activity::store($importer, $contact['abook_xchan'], $AS, $item);
|
||||
}
|
||||
}
|
||||
}
|
||||
logger("onepoll: $total messages processed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update the poco details for this connection
|
||||
$r = q("SELECT xlink_id from xlink where xlink_xchan = '%s' and xlink_updated > %s - INTERVAL %s and xlink_static = 0 limit 1",
|
||||
intval($contact['xchan_hash']),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('1 DAY')
|
||||
);
|
||||
|
||||
if($contact['xchan_connurl']) {
|
||||
$r = q("SELECT xlink_id from xlink
|
||||
where xlink_xchan = '%s' and xlink_updated > %s - INTERVAL %s and xlink_static = 0 limit 1",
|
||||
intval($contact['xchan_hash']),
|
||||
db_utcnow(), db_quoteinterval('1 DAY')
|
||||
);
|
||||
if(! $r) {
|
||||
poco_load($contact['xchan_hash'],$contact['xchan_connurl']);
|
||||
}
|
||||
if (!$r) {
|
||||
poco_load($contact['xchan_hash'], $contact['xchan_connurl']);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -4,201 +4,193 @@ namespace Zotlabs\Daemon;
|
||||
|
||||
class Poller {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
$maxsysload = intval(get_config('system','maxloadavg'));
|
||||
if($maxsysload < 1)
|
||||
$maxsysload = intval(get_config('system', 'maxloadavg'));
|
||||
if ($maxsysload < 1)
|
||||
$maxsysload = 50;
|
||||
if(function_exists('sys_getloadavg')) {
|
||||
if (function_exists('sys_getloadavg')) {
|
||||
$load = sys_getloadavg();
|
||||
if(intval($load[0]) > $maxsysload) {
|
||||
if (intval($load[0]) > $maxsysload) {
|
||||
logger('system: load ' . $load . ' too high. Poller deferred to next scheduled run.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$interval = intval(get_config('system','poll_interval'));
|
||||
if(! $interval)
|
||||
$interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval')));
|
||||
$interval = intval(get_config('system', 'poll_interval'));
|
||||
if (!$interval)
|
||||
$interval = ((get_config('system', 'delivery_interval') === false) ? 3 : intval(get_config('system', 'delivery_interval')));
|
||||
|
||||
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
|
||||
$lockfile = 'store/[data]/poller';
|
||||
if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
|
||||
&& (! get_config('system','override_poll_lockfile'))) {
|
||||
if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
|
||||
&& (!get_config('system', 'override_poll_lockfile'))) {
|
||||
logger("poller: Already running");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
|
||||
$x = '';
|
||||
file_put_contents($lockfile, $x);
|
||||
|
||||
logger('poller: start');
|
||||
|
||||
|
||||
$manual_id = 0;
|
||||
$generation = 0;
|
||||
$force = false;
|
||||
|
||||
$force = false;
|
||||
$restart = false;
|
||||
|
||||
if(($argc > 1) && ($argv[1] == 'force'))
|
||||
if (($argc > 1) && ($argv[1] == 'force'))
|
||||
$force = true;
|
||||
|
||||
if(($argc > 1) && ($argv[1] == 'restart')) {
|
||||
$restart = true;
|
||||
if (($argc > 1) && ($argv[1] == 'restart')) {
|
||||
$generation = intval($argv[2]);
|
||||
if(! $generation)
|
||||
killme();
|
||||
if (!$generation)
|
||||
return;
|
||||
}
|
||||
|
||||
if(($argc > 1) && intval($argv[1])) {
|
||||
if (($argc > 1) && intval($argv[1])) {
|
||||
$manual_id = intval($argv[1]);
|
||||
$force = true;
|
||||
}
|
||||
|
||||
|
||||
$sql_extra = (($manual_id) ? " AND abook_id = " . intval($manual_id) . " " : "");
|
||||
|
||||
reload_plugins();
|
||||
|
||||
$d = datetime_convert();
|
||||
|
||||
// Only poll from those with suitable relationships
|
||||
|
||||
$abandon_sql = (($abandon_days)
|
||||
? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days).' DAY'))
|
||||
: ''
|
||||
$abandon_days = intval(get_config('system', 'account_abandon_days', 0));
|
||||
$abandon_sql = (($abandon_days)
|
||||
? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days) . ' DAY'))
|
||||
: ''
|
||||
);
|
||||
|
||||
$randfunc = db_getfunc('RAND');
|
||||
|
||||
|
||||
$contacts = q("SELECT abook.abook_updated, abook.abook_connected, abook.abook_feed,
|
||||
abook.abook_channel, abook.abook_id, abook.abook_archived, abook.abook_pending,
|
||||
abook.abook_ignored, abook.abook_blocked,
|
||||
xchan.xchan_network,
|
||||
account.account_lastlog, account.account_flags
|
||||
FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash
|
||||
account.account_lastlog, account.account_flags
|
||||
FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash
|
||||
LEFT JOIN account on abook_account = account_id
|
||||
where abook_self = 0
|
||||
$sql_extra
|
||||
$sql_extra
|
||||
AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY $randfunc",
|
||||
intval(ACCOUNT_OK),
|
||||
intval(ACCOUNT_UNVERIFIED) // FIXME
|
||||
);
|
||||
|
||||
if($contacts) {
|
||||
if ($contacts) {
|
||||
foreach ($contacts as $contact) {
|
||||
|
||||
foreach($contacts as $contact) {
|
||||
|
||||
$update = false;
|
||||
$update = false;
|
||||
|
||||
$t = $contact['abook_updated'];
|
||||
$c = $contact['abook_connected'];
|
||||
|
||||
if(intval($contact['abook_feed'])) {
|
||||
$min = service_class_fetch($contact['abook_channel'],'minimum_feedcheck_minutes');
|
||||
if(! $min)
|
||||
$min = intval(get_config('system','minimum_feedcheck_minutes'));
|
||||
if(! $min)
|
||||
if (intval($contact['abook_feed'])) {
|
||||
$min = service_class_fetch($contact['abook_channel'], 'minimum_feedcheck_minutes');
|
||||
if (!$min)
|
||||
$min = intval(get_config('system', 'minimum_feedcheck_minutes'));
|
||||
if (!$min)
|
||||
$min = 60;
|
||||
$x = datetime_convert('UTC','UTC',"now - $min minutes");
|
||||
if($c < $x) {
|
||||
Master::Summon(array('Onepoll',$contact['abook_id']));
|
||||
if($interval)
|
||||
@time_sleep_until(microtime(true) + (float) $interval);
|
||||
$x = datetime_convert('UTC', 'UTC', "now - $min minutes");
|
||||
if ($c < $x) {
|
||||
Master::Summon(['Onepoll', $contact['abook_id']]);
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if(! in_array($contact['xchan_network'],['zot','zot6']))
|
||||
if ($contact['xchan_network'] !== 'zot6')
|
||||
continue;
|
||||
|
||||
if($c == $t) {
|
||||
if(datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day"))
|
||||
if ($c == $t) {
|
||||
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day"))
|
||||
$update = true;
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
// if we've never connected with them, start the mark for death countdown from now
|
||||
|
||||
if($c <= NULL_DATE) {
|
||||
$r = q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
|
||||
if ($c <= NULL_DATE) {
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
$c = datetime_convert();
|
||||
$c = datetime_convert();
|
||||
$update = true;
|
||||
}
|
||||
|
||||
// He's dead, Jim
|
||||
|
||||
if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) {
|
||||
$r = q("update abook set abook_archived = 1 where abook_id = %d",
|
||||
if (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $c . " + 30 day")) > 0) {
|
||||
q("update abook set abook_archived = 1 where abook_id = %d",
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
$update = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(intval($contact['abook_archived'])) {
|
||||
$update = false;
|
||||
if (intval($contact['abook_archived'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// might be dead, so maybe don't poll quite so often
|
||||
|
||||
|
||||
// recently deceased, so keep up the regular schedule for 3 days
|
||||
|
||||
if((strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 3 day")) > 0)
|
||||
&& (strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 1 day")) > 0))
|
||||
|
||||
if ((strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $c . " + 3 day")) > 0)
|
||||
&& (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $t . " + 1 day")) > 0))
|
||||
$update = true;
|
||||
|
||||
// After that back off and put them on a morphine drip
|
||||
|
||||
if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 2 day")) > 0) {
|
||||
if (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $t . " + 2 day")) > 0) {
|
||||
$update = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked']))
|
||||
if (intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked']))
|
||||
continue;
|
||||
|
||||
if((! $update) && (! $force))
|
||||
continue;
|
||||
if ((!$update) && (!$force))
|
||||
continue;
|
||||
|
||||
Master::Summon(array('Onepoll',$contact['abook_id']));
|
||||
if($interval)
|
||||
@time_sleep_until(microtime(true) + (float) $interval);
|
||||
Master::Summon(['Onepoll', $contact['abook_id']]);
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
$dirmode = intval(get_config('system', 'directory_mode'));
|
||||
|
||||
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
|
||||
$r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last <= '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ",
|
||||
intval(UPDATE_FLAGS_UPDATED),
|
||||
dbesc(NULL_DATE),
|
||||
db_utcnow(), db_quoteinterval('7 DAY')
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
|
||||
// If they didn't respond when we attempted before, back off to once a day
|
||||
// After 7 days we won't bother anymore
|
||||
|
||||
if($rr['ud_last'] > NULL_DATE)
|
||||
if($rr['ud_last'] > datetime_convert('UTC','UTC', 'now - 1 day'))
|
||||
if ($rr['ud_last'] > NULL_DATE)
|
||||
if ($rr['ud_last'] > datetime_convert('UTC', 'UTC', 'now - 1 day'))
|
||||
continue;
|
||||
Master::Summon(array('Onedirsync',$rr['ud_id']));
|
||||
if($interval)
|
||||
@time_sleep_until(microtime(true) + (float) $interval);
|
||||
Master::Summon(['Onedirsync', $rr['ud_id']]);
|
||||
if ($interval)
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_config('system','lastpoll',datetime_convert());
|
||||
set_config('system', 'lastpoll', datetime_convert());
|
||||
|
||||
//All done - clear the lockfile
|
||||
//All done - clear the lockfile
|
||||
|
||||
@unlink($lockfile);
|
||||
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/queue_fn.php');
|
||||
require_once('include/zot.php');
|
||||
use Zotlabs\Lib\Queue as LibQueue;
|
||||
|
||||
class Queue {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
require_once('include/items.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
if($argc > 1)
|
||||
if ($argc > 1)
|
||||
$queue_id = $argv[1];
|
||||
else
|
||||
$queue_id = EMPTY_STR;
|
||||
@@ -25,11 +24,10 @@ class Queue {
|
||||
$r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s",
|
||||
db_utcnow(), db_quoteinterval('3 DAY')
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
$site_url = '';
|
||||
$h = parse_url($rr['outq_posturl']);
|
||||
$desturl = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$h = parse_url($rr['outq_posturl']);
|
||||
$desturl = $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : '');
|
||||
q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s",
|
||||
dbesc($desturl),
|
||||
db_utcnow(), db_quoteinterval('1 MONTH')
|
||||
@@ -37,11 +35,11 @@ class Queue {
|
||||
}
|
||||
}
|
||||
|
||||
$r = q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s",
|
||||
q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s",
|
||||
db_utcnow(), db_quoteinterval('3 DAY')
|
||||
);
|
||||
|
||||
if($queue_id) {
|
||||
if ($queue_id) {
|
||||
$r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
|
||||
dbesc($queue_id)
|
||||
);
|
||||
@@ -49,17 +47,17 @@ class Queue {
|
||||
else {
|
||||
|
||||
// For the first 12 hours we'll try to deliver every 15 minutes
|
||||
// After that, we'll only attempt delivery once per hour.
|
||||
// This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
|
||||
// After that, we'll only attempt delivery once per hour.
|
||||
// This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
|
||||
// so that we don't start off a thousand deliveries for a couple of dead hubs.
|
||||
// The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
|
||||
// Other drivers will have to do something different here and may need their own query.
|
||||
|
||||
// Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
|
||||
|
||||
// Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
|
||||
// "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
|
||||
// or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
|
||||
// the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
|
||||
// or twice a day.
|
||||
// the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
|
||||
// or twice a day.
|
||||
|
||||
$sqlrandfunc = db_getfunc('rand');
|
||||
|
||||
@@ -67,19 +65,19 @@ class Queue {
|
||||
db_utcnow()
|
||||
);
|
||||
while ($r) {
|
||||
foreach($r as $rv) {
|
||||
queue_deliver($rv);
|
||||
foreach ($r as $rv) {
|
||||
LibQueue::deliver($rv);
|
||||
}
|
||||
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
|
||||
db_utcnow()
|
||||
);
|
||||
}
|
||||
}
|
||||
if(! $r)
|
||||
if (!$r)
|
||||
return;
|
||||
|
||||
foreach($r as $rv) {
|
||||
queue_deliver($rv);
|
||||
foreach ($r as $rv) {
|
||||
LibQueue::deliver($rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/queue_fn.php');
|
||||
|
||||
|
||||
class Ratenotif {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
require_once("datetime.php");
|
||||
require_once('include/items.php');
|
||||
|
||||
if($argc < 3)
|
||||
return;
|
||||
|
||||
|
||||
logger('ratenotif: invoked: ' . print_r($argv,true), LOGGER_DEBUG);
|
||||
|
||||
$cmd = $argv[1];
|
||||
|
||||
$item_id = $argv[2];
|
||||
|
||||
|
||||
if($cmd === 'rating') {
|
||||
$r = q("select * from xlink where xlink_id = %d and xlink_static = 1 limit 1",
|
||||
intval($item_id)
|
||||
);
|
||||
if(! $r) {
|
||||
logger('rating not found');
|
||||
return;
|
||||
}
|
||||
|
||||
$encoded_item = array(
|
||||
'type' => 'rating',
|
||||
'encoding' => 'zot',
|
||||
'target' => $r[0]['xlink_link'],
|
||||
'rating' => intval($r[0]['xlink_rating']),
|
||||
'rating_text' => $r[0]['xlink_rating_text'],
|
||||
'signature' => $r[0]['xlink_sig'],
|
||||
'edited' => $r[0]['xlink_updated']
|
||||
);
|
||||
}
|
||||
|
||||
$channel = channelx_by_hash($r[0]['xlink_xchan']);
|
||||
if(! $channel) {
|
||||
logger('no channel');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$primary = get_directory_primary();
|
||||
|
||||
if(! $primary)
|
||||
return;
|
||||
|
||||
|
||||
$interval = ((get_config('system','delivery_interval') !== false)
|
||||
? intval(get_config('system','delivery_interval')) : 2 );
|
||||
|
||||
$deliveries_per_process = intval(get_config('system','delivery_batch_count'));
|
||||
|
||||
if($deliveries_per_process <= 0)
|
||||
$deliveries_per_process = 1;
|
||||
|
||||
$deliver = array();
|
||||
|
||||
$x = z_fetch_url($primary . '/regdir');
|
||||
if($x['success']) {
|
||||
$j = json_decode($x['body'],true);
|
||||
if($j && $j['success'] && is_array($j['directories'])) {
|
||||
|
||||
foreach($j['directories'] as $h) {
|
||||
if($h == z_root())
|
||||
continue;
|
||||
|
||||
$hash = random_string();
|
||||
$n = zot_build_packet($channel,'notify',null,null,'',$hash);
|
||||
|
||||
queue_insert(array(
|
||||
'hash' => $hash,
|
||||
'account_id' => $channel['channel_account_id'],
|
||||
'channel_id' => $channel['channel_id'],
|
||||
'posturl' => $h . '/post',
|
||||
'notify' => $n,
|
||||
'msg' => json_encode($encoded_item)
|
||||
));
|
||||
|
||||
|
||||
$x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
|
||||
if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',300))) {
|
||||
logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
|
||||
update_queue_item($hash);
|
||||
continue;
|
||||
}
|
||||
|
||||
$deliver[] = $hash;
|
||||
|
||||
if(count($deliver) >= $deliveries_per_process) {
|
||||
Master::Summon(array('Deliver',$deliver));
|
||||
$deliver = array();
|
||||
if($interval)
|
||||
@time_sleep_until(microtime(true) + (float) $interval);
|
||||
}
|
||||
}
|
||||
|
||||
// catch any stragglers
|
||||
|
||||
if(count($deliver)) {
|
||||
Master::Summon(array('Deliver',$deliver));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger('ratenotif: complete.');
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,30 +5,30 @@ namespace Zotlabs\Daemon;
|
||||
|
||||
class Thumbnail {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
if(! $argc == 2)
|
||||
if (!$argc == 2)
|
||||
return;
|
||||
|
||||
$c = q("select * from attach where hash = '%s' ",
|
||||
dbesc($argv[1])
|
||||
);
|
||||
|
||||
if(! $c)
|
||||
if (!$c)
|
||||
return;
|
||||
|
||||
$attach = $c[0];
|
||||
|
||||
$preview_style = intval(get_config('system','thumbnail_security',0));
|
||||
$preview_width = intval(get_config('system','thumbnail_width',300));
|
||||
$preview_height = intval(get_config('system','thumbnail_height',300));
|
||||
$preview_style = intval(get_config('system', 'thumbnail_security', 0));
|
||||
$preview_width = intval(get_config('system', 'thumbnail_width', 300));
|
||||
$preview_height = intval(get_config('system', 'thumbnail_height', 300));
|
||||
|
||||
$p = [
|
||||
'attach' => $attach,
|
||||
'preview_style' => $preview_style,
|
||||
'preview_width' => $preview_width,
|
||||
'preview_height' => $preview_height,
|
||||
'thumbnail' => null
|
||||
'thumbnail' => null
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -40,39 +40,38 @@ class Thumbnail {
|
||||
* * \e string \b thumbnail
|
||||
*/
|
||||
|
||||
call_hooks('thumbnail',$p);
|
||||
if($p['thumbnail']) {
|
||||
call_hooks('thumbnail', $p);
|
||||
if ($p['thumbnail']) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$default_controller = null;
|
||||
|
||||
|
||||
$files = glob('Zotlabs/Thumbs/*.php');
|
||||
if($files) {
|
||||
foreach($files as $f) {
|
||||
$clsname = '\\Zotlabs\\Thumbs\\' . ucfirst(basename($f,'.php'));
|
||||
if(class_exists($clsname)) {
|
||||
if ($files) {
|
||||
foreach ($files as $f) {
|
||||
$clsname = '\\Zotlabs\\Thumbs\\' . ucfirst(basename($f, '.php'));
|
||||
if (class_exists($clsname)) {
|
||||
$x = new $clsname();
|
||||
if(method_exists($x,'Match')) {
|
||||
if (method_exists($x, 'Match')) {
|
||||
$matched = $x->Match($attach['filetype']);
|
||||
if($matched) {
|
||||
$x->Thumb($attach,$preview_style,$preview_width,$preview_height);
|
||||
if ($matched) {
|
||||
$x->Thumb($attach, $preview_style, $preview_width, $preview_height);
|
||||
}
|
||||
}
|
||||
if(method_exists($x,'MatchDefault')) {
|
||||
$default_matched = $x->MatchDefault(substr($attach['filetype'],0,strpos($attach['filetype'],'/')));
|
||||
if($default_matched) {
|
||||
if (method_exists($x, 'MatchDefault')) {
|
||||
$default_matched = $x->MatchDefault(substr($attach['filetype'], 0, strpos($attach['filetype'], '/')));
|
||||
if ($default_matched) {
|
||||
$default_controller = $x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(($default_controller)
|
||||
&& ((! file_exists(dbunescbin($attach['content']) . '.thumb'))
|
||||
if (($default_controller)
|
||||
&& ((!file_exists(dbunescbin($attach['content']) . '.thumb'))
|
||||
|| (filectime(dbunescbin($attach['content']) . 'thumb') < (time() - 60)))) {
|
||||
$default_controller->Thumb($attach,$preview_style,$preview_width,$preview_height);
|
||||
$default_controller->Thumb($attach, $preview_style, $preview_width, $preview_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
150
Zotlabs/Lib/ASCollection.php
Normal file
150
Zotlabs/Lib/ASCollection.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
/**
|
||||
* Class for dealing with fetching ActivityStreams collections (ordered or unordered, normal or paged).
|
||||
* Construct with either an existing object or url and an optional channel to sign requests.
|
||||
* $direction is 0 (default) to fetch from the beginning, and 1 to fetch from the end and reverse order the resultant array.
|
||||
* An optional limit to the number of records returned may also be specified.
|
||||
* Use $class->get() to return an array of collection members.
|
||||
*/
|
||||
class ASCollection {
|
||||
|
||||
private $channel = null;
|
||||
private $nextpage = null;
|
||||
private $limit = 0;
|
||||
private $direction = 0; // 0 = forward, 1 = reverse
|
||||
private $data = [];
|
||||
private $history = [];
|
||||
|
||||
function __construct($obj, $channel = null, $direction = 0, $limit = 0) {
|
||||
|
||||
$this->channel = $channel;
|
||||
$this->direction = $direction;
|
||||
$this->limit = $limit;
|
||||
|
||||
if (is_array($obj)) {
|
||||
$data = $obj;
|
||||
}
|
||||
|
||||
if (is_string($obj)) {
|
||||
$data = Activity::fetch($obj, $channel);
|
||||
$this->history[] = $obj;
|
||||
}
|
||||
|
||||
if (!is_array($data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array($data['type'], ['Collection', 'OrderedCollection', 'OrderedCollectionPage'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->direction) {
|
||||
if (array_key_exists('last', $data) && $data['last']) {
|
||||
$this->nextpage = $data['last'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (array_key_exists('first', $data) && $data['first']) {
|
||||
$this->nextpage = $data['first'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['items']) && is_array($data['items'])) {
|
||||
$this->data = (($this->direction) ? array_reverse($data['items']) : $data['items']);
|
||||
}
|
||||
elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) {
|
||||
$this->data = (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']);
|
||||
}
|
||||
|
||||
if ($this->limit) {
|
||||
if (count($this->data) > $limit) {
|
||||
$this->data = array_slice($this->data, 0, $limit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
$x = $this->next();
|
||||
} while ($x);
|
||||
}
|
||||
|
||||
function get() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
function next() {
|
||||
|
||||
if (!$this->nextpage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($this->nextpage)) {
|
||||
$data = $this->nextpage;
|
||||
}
|
||||
|
||||
if (is_string($this->nextpage)) {
|
||||
if (in_array($this->nextpage, $this->history)) {
|
||||
// recursion detected
|
||||
return false;
|
||||
}
|
||||
$data = Activity::fetch($this->nextpage, $this->channel);
|
||||
$this->history[] = $this->nextpage;
|
||||
}
|
||||
|
||||
if (!is_array($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!in_array($data['type'], ['CollectionPage', 'OrderedCollectionPage'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->setnext($data);
|
||||
|
||||
if (isset($data['items']) && is_array($data['items'])) {
|
||||
$this->data = array_merge($this->data, (($this->direction) ? array_reverse($data['items']) : $data['items']));
|
||||
}
|
||||
elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) {
|
||||
$this->data = array_merge($this->data, (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']));
|
||||
}
|
||||
|
||||
if ($this->limit) {
|
||||
if (count($this->data) > $this->limit) {
|
||||
$this->data = array_slice($this->data, 0, $this->limit);
|
||||
$this->nextpage = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function setnext($data) {
|
||||
if ($this->direction) {
|
||||
if (array_key_exists('prev', $data) && $data['prev']) {
|
||||
$this->nextpage = $data['prev'];
|
||||
}
|
||||
elseif (array_key_exists('first', $data) && $data['first']) {
|
||||
$this->nextpage = $data['first'];
|
||||
}
|
||||
else {
|
||||
$this->nextpage = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (array_key_exists('next', $data) && $data['next']) {
|
||||
$this->nextpage = $data['next'];
|
||||
}
|
||||
elseif (array_key_exists('last', $data) && $data['last']) {
|
||||
$this->nextpage = $data['last'];
|
||||
}
|
||||
else {
|
||||
$this->nextpage = false;
|
||||
}
|
||||
}
|
||||
logger('nextpage: ' . $this->nextpage, LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
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
@@ -7,25 +7,24 @@ namespace Zotlabs\Lib;
|
||||
*
|
||||
* Parses an ActivityStream JSON string.
|
||||
*/
|
||||
|
||||
class ActivityStreams {
|
||||
|
||||
public $raw = null;
|
||||
public $data = null;
|
||||
public $valid = false;
|
||||
public $deleted = false;
|
||||
public $id = '';
|
||||
public $parent_id = '';
|
||||
public $type = '';
|
||||
public $actor = null;
|
||||
public $obj = null;
|
||||
public $tgt = null;
|
||||
public $origin = null;
|
||||
public $owner = null;
|
||||
public $signer = null;
|
||||
public $ldsig = null;
|
||||
public $sigok = false;
|
||||
public $recips = null;
|
||||
public $raw = null;
|
||||
public $data = null;
|
||||
public $valid = false;
|
||||
public $deleted = false;
|
||||
public $id = '';
|
||||
public $parent_id = '';
|
||||
public $type = '';
|
||||
public $actor = null;
|
||||
public $obj = null;
|
||||
public $tgt = null;
|
||||
public $origin = null;
|
||||
public $owner = null;
|
||||
public $signer = null;
|
||||
public $ldsig = null;
|
||||
public $sigok = false;
|
||||
public $recips = null;
|
||||
public $raw_recips = null;
|
||||
|
||||
/**
|
||||
@@ -37,29 +36,29 @@ class ActivityStreams {
|
||||
*/
|
||||
function __construct($string) {
|
||||
|
||||
$this->raw = $string;
|
||||
$this->raw = $string;
|
||||
|
||||
if(is_array($string)) {
|
||||
if (is_array($string)) {
|
||||
$this->data = $string;
|
||||
}
|
||||
else {
|
||||
$this->data = json_decode($string, true);
|
||||
}
|
||||
|
||||
if($this->data) {
|
||||
if ($this->data) {
|
||||
|
||||
// verify and unpack JSalmon signature if present
|
||||
|
||||
if(is_array($this->data) && array_key_exists('signed',$this->data)) {
|
||||
|
||||
if (is_array($this->data) && array_key_exists('signed', $this->data)) {
|
||||
$ret = JSalmon::verify($this->data);
|
||||
$tmp = JSalmon::unpack($this->data['data']);
|
||||
if($ret && $ret['success']) {
|
||||
if($ret['signer']) {
|
||||
$saved = json_encode($this->data,JSON_UNESCAPED_SLASHES);
|
||||
$this->data = $tmp;
|
||||
$this->data['signer'] = $ret['signer'];
|
||||
if ($ret && $ret['success']) {
|
||||
if ($ret['signer']) {
|
||||
$saved = json_encode($this->data, JSON_UNESCAPED_SLASHES);
|
||||
$this->data = $tmp;
|
||||
$this->data['signer'] = $ret['signer'];
|
||||
$this->data['signed_data'] = $saved;
|
||||
if($ret['hubloc']) {
|
||||
if ($ret['hubloc']) {
|
||||
$this->data['hubloc'] = $ret['hubloc'];
|
||||
}
|
||||
}
|
||||
@@ -68,51 +67,57 @@ class ActivityStreams {
|
||||
|
||||
$this->valid = true;
|
||||
|
||||
if(array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) {
|
||||
if($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
|
||||
if (array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) {
|
||||
if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
|
||||
$this->deleted = $this->data['actor'];
|
||||
$this->valid = false;
|
||||
$this->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($this->is_valid()) {
|
||||
if ($this->is_valid()) {
|
||||
$this->id = $this->get_property_obj('id');
|
||||
$this->type = $this->get_primary_type();
|
||||
$this->actor = $this->get_actor('actor','','');
|
||||
$this->actor = $this->get_actor('actor', '', '');
|
||||
$this->obj = $this->get_compound_property('object');
|
||||
$this->tgt = $this->get_compound_property('target');
|
||||
$this->origin = $this->get_compound_property('origin');
|
||||
$this->recips = $this->collect_recips();
|
||||
|
||||
$this->ldsig = $this->get_compound_property('signature');
|
||||
if($this->ldsig) {
|
||||
$this->signer = $this->get_compound_property('creator',$this->ldsig);
|
||||
if($this->signer && is_array($this->signer) && array_key_exists('publicKey',$this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
|
||||
$this->sigok = LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
|
||||
if ($this->ldsig) {
|
||||
$this->signer = $this->get_compound_property('creator', $this->ldsig);
|
||||
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
|
||||
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
|
||||
}
|
||||
}
|
||||
|
||||
if(! $this->obj) {
|
||||
$this->obj = $this->data;
|
||||
if (!$this->obj) {
|
||||
$this->obj = $this->data;
|
||||
$this->type = 'Create';
|
||||
if(! $this->actor) {
|
||||
$this->actor = $this->get_actor('attributedTo',$this->obj);
|
||||
if (!$this->actor) {
|
||||
$this->actor = $this->get_actor('attributedTo', $this->obj);
|
||||
}
|
||||
}
|
||||
|
||||
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'])
|
||||
$this->tgt['actor'] = $this->get_actor('actor',$this->tgt);
|
||||
|
||||
// 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'])
|
||||
$this->tgt['actor'] = $this->get_actor('actor', $this->tgt);
|
||||
|
||||
$this->parent_id = $this->get_property_obj('inReplyTo');
|
||||
|
||||
if((! $this->parent_id) && is_array($this->obj)) {
|
||||
if ((!$this->parent_id) && is_array($this->obj)) {
|
||||
$this->parent_id = $this->obj['inReplyTo'];
|
||||
}
|
||||
if((! $this->parent_id) && is_array($this->obj)) {
|
||||
if ((!$this->parent_id) && is_array($this->obj)) {
|
||||
$this->parent_id = $this->obj['id'];
|
||||
}
|
||||
}
|
||||
@@ -140,15 +145,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))
|
||||
$this->raw_recips = [];
|
||||
|
||||
$this->raw_recips[$f] = $x;
|
||||
$fields = ['to', 'cc', 'bto', 'bcc', 'audience'];
|
||||
foreach ($fields as $f) {
|
||||
$y = $this->get_compound_property($f, $base, $namespace);
|
||||
if ($y) {
|
||||
if (!is_array($this->raw_recips)) {
|
||||
$this->raw_recips = [];
|
||||
}
|
||||
|
||||
if (!is_array($y)) {
|
||||
$y = [$y];
|
||||
}
|
||||
$this->raw_recips[$f] = $y;
|
||||
$x = array_merge($x, $y);
|
||||
}
|
||||
}
|
||||
// not yet ready for prime time
|
||||
@@ -156,21 +166,21 @@ class ActivityStreams {
|
||||
return $x;
|
||||
}
|
||||
|
||||
function expand($arr,$base = '',$namespace = '') {
|
||||
function expand($arr, $base = '', $namespace = '') {
|
||||
$ret = [];
|
||||
|
||||
// right now use a hardwired recursion depth of 5
|
||||
|
||||
for($z = 0; $z < 5; $z ++) {
|
||||
if(is_array($arr) && $arr) {
|
||||
foreach($arr as $a) {
|
||||
if(is_array($a)) {
|
||||
for ($z = 0; $z < 5; $z++) {
|
||||
if (is_array($arr) && $arr) {
|
||||
foreach ($arr as $a) {
|
||||
if (is_array($a)) {
|
||||
$ret[] = $a;
|
||||
}
|
||||
else {
|
||||
$x = $this->get_compound_property($a,$base,$namespace);
|
||||
if($x) {
|
||||
$ret = array_merge($ret,$x);
|
||||
$x = $this->get_compound_property($a, $base, $namespace);
|
||||
if ($x) {
|
||||
$ret = array_merge($ret, $x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,33 +201,33 @@ class ActivityStreams {
|
||||
*/
|
||||
function get_namespace($base, $namespace) {
|
||||
|
||||
if(! $namespace)
|
||||
if (!$namespace)
|
||||
return '';
|
||||
|
||||
$key = null;
|
||||
|
||||
foreach( [ $this->data, $base ] as $b ) {
|
||||
if(! $b)
|
||||
foreach ([$this->data, $base] as $b) {
|
||||
if (!$b)
|
||||
continue;
|
||||
|
||||
if(array_key_exists('@context', $b)) {
|
||||
if(is_array($b['@context'])) {
|
||||
foreach($b['@context'] as $ns) {
|
||||
if(is_array($ns)) {
|
||||
foreach($ns as $k => $v) {
|
||||
if($namespace === $v)
|
||||
if (array_key_exists('@context', $b)) {
|
||||
if (is_array($b['@context'])) {
|
||||
foreach ($b['@context'] as $ns) {
|
||||
if (is_array($ns)) {
|
||||
foreach ($ns as $k => $v) {
|
||||
if ($namespace === $v)
|
||||
$key = $k;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($namespace === $ns) {
|
||||
if ($namespace === $ns) {
|
||||
$key = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($namespace === $b['@context']) {
|
||||
if ($namespace === $b['@context']) {
|
||||
$key = '';
|
||||
}
|
||||
}
|
||||
@@ -237,14 +247,14 @@ class ActivityStreams {
|
||||
*/
|
||||
function get_property_obj($property, $base = '', $namespace = '') {
|
||||
$prefix = $this->get_namespace($base, $namespace);
|
||||
if($prefix === null)
|
||||
if ($prefix === null)
|
||||
return null;
|
||||
|
||||
$base = (($base) ? $base : $this->data);
|
||||
$base = (($base) ? $base : $this->data);
|
||||
$propname = (($prefix) ? $prefix . ':' : '') . $property;
|
||||
|
||||
if(! is_array($base)) {
|
||||
btlogger('not an array: ' . print_r($base,true));
|
||||
if (!is_array($base)) {
|
||||
btlogger('not an array: ' . print_r($base, true));
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -263,12 +273,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', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact']));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,25 +297,26 @@ class ActivityStreams {
|
||||
* @return NULL|mixed
|
||||
*/
|
||||
|
||||
function get_actor($property,$base='',$namespace = '') {
|
||||
function get_actor($property, $base = '', $namespace = '') {
|
||||
$x = $this->get_property_obj($property, $base, $namespace);
|
||||
if($this->is_url($x)) {
|
||||
if ($this->is_url($x)) {
|
||||
|
||||
// SECURITY: If we have already stored the actor profile, re-generate it
|
||||
// SECURITY: If we have already stored the actor profile, re-generate it
|
||||
// from cached data - don't refetch it from the network
|
||||
|
||||
$r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
|
||||
$r = q("select * from xchan join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s'",
|
||||
dbesc($x)
|
||||
);
|
||||
if($r) {
|
||||
$y = Activity::encode_person($r[0]);
|
||||
if ($r) {
|
||||
$r = Libzot::zot_record_preferred($r);
|
||||
$y = Activity::encode_person($r);
|
||||
$y['cached'] = true;
|
||||
return $y;
|
||||
}
|
||||
}
|
||||
$actor = $this->get_compound_property($property,$base,$namespace,true);
|
||||
if(is_array($actor) && self::is_an_actor($actor['type'])) {
|
||||
if(array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) {
|
||||
$actor = $this->get_compound_property($property, $base, $namespace, true);
|
||||
if (is_array($actor) && self::is_an_actor($actor['type'])) {
|
||||
if (array_key_exists('id', $actor) && (!array_key_exists('inbox', $actor))) {
|
||||
$actor = $this->fetch_property($actor['id']);
|
||||
}
|
||||
return $actor;
|
||||
@@ -318,7 +336,7 @@ class ActivityStreams {
|
||||
*/
|
||||
function get_compound_property($property, $base = '', $namespace = '', $first = false) {
|
||||
$x = $this->get_property_obj($property, $base, $namespace);
|
||||
if($this->is_url($x)) {
|
||||
if ($this->is_url($x)) {
|
||||
$y = $this->fetch_property($x);
|
||||
if (is_array($y)) {
|
||||
$x = $y;
|
||||
@@ -326,23 +344,23 @@ class ActivityStreams {
|
||||
}
|
||||
|
||||
// verify and unpack JSalmon signature if present
|
||||
|
||||
if(is_array($x) && array_key_exists('signed',$x)) {
|
||||
|
||||
if (is_array($x) && array_key_exists('signed', $x)) {
|
||||
$ret = JSalmon::verify($x);
|
||||
$tmp = JSalmon::unpack($x['data']);
|
||||
if($ret && $ret['success']) {
|
||||
if($ret['signer']) {
|
||||
$saved = json_encode($x,JSON_UNESCAPED_SLASHES);
|
||||
$x = $tmp;
|
||||
$x['signer'] = $ret['signer'];
|
||||
if ($ret && $ret['success']) {
|
||||
if ($ret['signer']) {
|
||||
$saved = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$x = $tmp;
|
||||
$x['signer'] = $ret['signer'];
|
||||
$x['signed_data'] = $saved;
|
||||
if($ret['hubloc']) {
|
||||
if ($ret['hubloc']) {
|
||||
$x['hubloc'] = $ret['hubloc'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if($first && is_array($x) && array_key_exists(0,$x)) {
|
||||
if ($first && is_array($x) && array_key_exists(0, $x)) {
|
||||
return $x[0];
|
||||
}
|
||||
|
||||
@@ -356,7 +374,7 @@ class ActivityStreams {
|
||||
* @return boolean
|
||||
*/
|
||||
function is_url($url) {
|
||||
if(($url) && (! is_array($url)) && (strpos($url, 'http') === 0)) {
|
||||
if (($url) && (!is_array($url)) && (strpos($url, 'http') === 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -371,13 +389,13 @@ class ActivityStreams {
|
||||
* @return NULL|mixed
|
||||
*/
|
||||
function get_primary_type($base = '', $namespace = '') {
|
||||
if(! $base)
|
||||
if (!$base)
|
||||
$base = $this->data;
|
||||
|
||||
$x = $this->get_property_obj('type', $base, $namespace);
|
||||
if(is_array($x)) {
|
||||
foreach($x as $y) {
|
||||
if(strpos($y, ':') === false) {
|
||||
if (is_array($x)) {
|
||||
foreach ($x as $y) {
|
||||
if (strpos($y, ':') === false) {
|
||||
return $y;
|
||||
}
|
||||
}
|
||||
@@ -391,18 +409,33 @@ class ActivityStreams {
|
||||
return $x;
|
||||
}
|
||||
|
||||
static function is_as_request($channel = null) {
|
||||
|
||||
static function is_as_request() {
|
||||
$hookdata = [];
|
||||
if ($channel)
|
||||
$hookdata['channel'] = $channel;
|
||||
|
||||
$x = getBestSupportedMimeType([
|
||||
'application/ld+json;profile="https://www.w3.org/ns/activitystreams"',
|
||||
'application/activity+json',
|
||||
'application/ld+json;profile="http://www.w3.org/ns/activitystreams"'
|
||||
]);
|
||||
$hookdata['data'] = ['application/x-zot-activity+json'];
|
||||
|
||||
return(($x) ? true : false);
|
||||
call_hooks('is_as_request', $hookdata);
|
||||
|
||||
$x = getBestSupportedMimeType($hookdata['data']);
|
||||
return (($x) ? true : false);
|
||||
|
||||
}
|
||||
|
||||
static function get_accept_header_string($channel = null) {
|
||||
|
||||
}
|
||||
$hookdata = [];
|
||||
if ($channel)
|
||||
$hookdata['channel'] = $channel;
|
||||
|
||||
$hookdata['data'] = 'application/x-zot-activity+json';
|
||||
|
||||
call_hooks('get_accept_header_string', $hookdata);
|
||||
|
||||
return $hookdata['data'];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
require_once('include/plugin.php');
|
||||
require_once('include/channel.php');
|
||||
|
||||
@@ -74,8 +76,8 @@ class Apps {
|
||||
'Directory',
|
||||
'Search',
|
||||
'Help',
|
||||
'Mail',
|
||||
'Profile Photo'
|
||||
'Profile Photo',
|
||||
'HQ'
|
||||
]);
|
||||
|
||||
/**
|
||||
@@ -306,7 +308,7 @@ class Apps {
|
||||
}
|
||||
}
|
||||
}
|
||||
if($ret) {
|
||||
if(isset($ret)) {
|
||||
if($translate)
|
||||
self::translate_system_apps($ret);
|
||||
|
||||
@@ -371,10 +373,9 @@ 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')
|
||||
'Channel Export' => t('Channel Export'),
|
||||
);
|
||||
|
||||
if(array_key_exists('name',$arr)) {
|
||||
@@ -524,7 +525,7 @@ class Apps {
|
||||
}
|
||||
elseif(remote_channel()) {
|
||||
$observer = \App::get_observer();
|
||||
if($observer && $observer['xchan_network'] === 'zot') {
|
||||
if($observer && $observer['xchan_network'] === 'zot6') {
|
||||
// some folks might have xchan_url redirected offsite, use the connurl
|
||||
$x = parse_url($observer['xchan_connurl']);
|
||||
if($x) {
|
||||
@@ -551,7 +552,7 @@ class Apps {
|
||||
'$app' => $papp,
|
||||
'$icon' => $icon,
|
||||
'$hosturl' => $hosturl,
|
||||
'$purchase' => (($papp['page'] && (! $installed)) ? t('Purchase') : ''),
|
||||
'$purchase' => ((isset($papp['page']) && (! $installed)) ? t('Purchase') : ''),
|
||||
'$installed' => $installed,
|
||||
'$action_label' => (($hosturl && in_array($mode, ['view','install'])) ? $install_action : ''),
|
||||
'$edit' => ((local_channel() && $installed && $mode == 'edit') ? t('Edit') : ''),
|
||||
@@ -559,12 +560,13 @@ class Apps {
|
||||
'$undelete' => ((local_channel() && $mode == 'edit') ? t('Undelete') : ''),
|
||||
'$settings_url' => ((local_channel() && $installed && $mode == 'list') ? $papp['settings_url'] : ''),
|
||||
'$deleted' => $papp['deleted'],
|
||||
'$feature' => (($papp['embed'] || $mode == 'edit') ? false : true),
|
||||
'$pin' => (($papp['embed'] || $mode == 'edit') ? false : true),
|
||||
'$feature' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
|
||||
'$pin' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
|
||||
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
|
||||
'$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
|
||||
'$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 +606,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 +672,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 +961,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;
|
||||
}
|
||||
}
|
||||
@@ -1278,58 +1277,58 @@ class Apps {
|
||||
|
||||
$ret['type'] = 'personal';
|
||||
|
||||
if($app['app_id'])
|
||||
if(!empty($app['app_id']))
|
||||
$ret['guid'] = $app['app_id'];
|
||||
|
||||
if($app['app_sig'])
|
||||
if(!empty($app['app_sig']))
|
||||
$ret['sig'] = $app['app_sig'];
|
||||
|
||||
if($app['app_author'])
|
||||
if(!empty($app['app_author']))
|
||||
$ret['author'] = $app['app_author'];
|
||||
|
||||
if($app['app_name'])
|
||||
if(!empty($app['app_name']))
|
||||
$ret['name'] = $app['app_name'];
|
||||
|
||||
if($app['app_desc'])
|
||||
if(!empty($app['app_desc']))
|
||||
$ret['desc'] = $app['app_desc'];
|
||||
|
||||
if($app['app_url'])
|
||||
if(!empty($app['app_url']))
|
||||
$ret['url'] = $app['app_url'];
|
||||
|
||||
if($app['app_photo'])
|
||||
if(!empty($app['app_photo']))
|
||||
$ret['photo'] = $app['app_photo'];
|
||||
|
||||
if($app['app_icon'])
|
||||
if(!empty($app['app_icon']))
|
||||
$ret['icon'] = $app['app_icon'];
|
||||
|
||||
if($app['app_version'])
|
||||
if(!empty($app['app_version']))
|
||||
$ret['version'] = $app['app_version'];
|
||||
|
||||
if($app['app_addr'])
|
||||
if(!empty($app['app_addr']))
|
||||
$ret['addr'] = $app['app_addr'];
|
||||
|
||||
if($app['app_price'])
|
||||
if(!empty($app['app_price']))
|
||||
$ret['price'] = $app['app_price'];
|
||||
|
||||
if($app['app_page'])
|
||||
if(!empty($app['app_page']))
|
||||
$ret['page'] = $app['app_page'];
|
||||
|
||||
if($app['app_requires'])
|
||||
if(!empty($app['app_requires']))
|
||||
$ret['requires'] = $app['app_requires'];
|
||||
|
||||
if($app['app_system'])
|
||||
if(!empty($app['app_system']))
|
||||
$ret['system'] = $app['app_system'];
|
||||
|
||||
if($app['app_options'])
|
||||
if(!empty($app['app_options']))
|
||||
$ret['options'] = $app['app_options'];
|
||||
|
||||
if($app['app_plugin'])
|
||||
if(!empty($app['app_plugin']))
|
||||
$ret['plugin'] = trim($app['app_plugin']);
|
||||
|
||||
if($app['app_deleted'])
|
||||
if(!empty($app['app_deleted']))
|
||||
$ret['deleted'] = $app['app_deleted'];
|
||||
|
||||
if($app['term']) {
|
||||
if(!empty($app['term']) && is_array($app['term'])) {
|
||||
$s = '';
|
||||
foreach($app['term'] as $t) {
|
||||
if($s)
|
||||
|
||||
@@ -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', '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;
|
||||
}
|
||||
}
|
||||
206
Zotlabs/Lib/Crypto.php
Normal file
206
Zotlabs/Lib/Crypto.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class Crypto {
|
||||
|
||||
public static $openssl_algorithms = [
|
||||
|
||||
// zot6 nickname, opensslname, keylength, ivlength
|
||||
|
||||
['aes256ctr', 'aes-256-ctr', 32, 16],
|
||||
['camellia256cfb', 'camellia-256-cfb', 32, 16],
|
||||
['cast5cfb', 'cast5-cfb', 16, 8],
|
||||
['aes256cbc', 'aes-256-cbc', 32, 16] // remove after legacy zot has been sunset
|
||||
|
||||
];
|
||||
|
||||
public static function methods() {
|
||||
$ret = [];
|
||||
|
||||
foreach (self::$openssl_algorithms as $ossl) {
|
||||
$ret[] = $ossl[0] . '.oaep';
|
||||
}
|
||||
|
||||
call_hooks('crypto_methods', $ret);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function signing_methods() {
|
||||
|
||||
$ret = ['sha256'];
|
||||
call_hooks('signing_methods', $ret);
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
public static function new_keypair($bits) {
|
||||
|
||||
$openssl_options = [
|
||||
'digest_alg' => 'sha1',
|
||||
'private_key_bits' => $bits,
|
||||
'encrypt_key' => false
|
||||
];
|
||||
|
||||
$conf = get_config('system', 'openssl_conf_file');
|
||||
|
||||
if ($conf) {
|
||||
$openssl_options['config'] = $conf;
|
||||
}
|
||||
|
||||
$result = openssl_pkey_new($openssl_options);
|
||||
|
||||
if (empty($result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get private key
|
||||
|
||||
$response = ['prvkey' => '', 'pubkey' => ''];
|
||||
|
||||
openssl_pkey_export($result, $response['prvkey']);
|
||||
|
||||
// Get public key
|
||||
$pkey = openssl_pkey_get_details($result);
|
||||
$response['pubkey'] = $pkey["key"];
|
||||
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
public static function sign($data, $key, $alg = 'sha256') {
|
||||
|
||||
if (!$key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sig = '';
|
||||
openssl_sign($data, $sig, $key, $alg);
|
||||
return $sig;
|
||||
}
|
||||
|
||||
public static function verify($data, $sig, $key, $alg = 'sha256') {
|
||||
|
||||
if (!$key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$verify = openssl_verify($data, $sig, $key, $alg);
|
||||
} catch (Exception $e) {
|
||||
$verify = (-1);
|
||||
}
|
||||
|
||||
if ($verify === (-1)) {
|
||||
while ($msg = openssl_error_string()) {
|
||||
logger('openssl_verify: ' . $msg, LOGGER_NORMAL, LOG_ERR);
|
||||
}
|
||||
btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR);
|
||||
}
|
||||
|
||||
return (($verify > 0) ? true : false);
|
||||
}
|
||||
|
||||
public static function encapsulate($data, $pubkey, $alg) {
|
||||
|
||||
if (!($alg && $pubkey)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$alg_base = $alg;
|
||||
$padding = OPENSSL_PKCS1_PADDING;
|
||||
|
||||
$exts = explode('.', $alg);
|
||||
if (count($exts) > 1) {
|
||||
switch ($exts[1]) {
|
||||
case 'oaep':
|
||||
$padding = OPENSSL_PKCS1_OAEP_PADDING;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$alg_base = $exts[0];
|
||||
}
|
||||
|
||||
$method = null;
|
||||
|
||||
foreach (self::$openssl_algorithms as $ossl) {
|
||||
if ($ossl[0] === $alg_base) {
|
||||
$method = $ossl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($method) {
|
||||
$result = ['encrypted' => true];
|
||||
|
||||
$key = openssl_random_pseudo_bytes(256);
|
||||
$iv = openssl_random_pseudo_bytes(256);
|
||||
|
||||
$key1 = substr($key, 0, $method[2]);
|
||||
$iv1 = substr($iv, 0, $method[3]);
|
||||
|
||||
$result['data'] = base64url_encode(openssl_encrypt($data, $method[1], $key1, OPENSSL_RAW_DATA, $iv1), true);
|
||||
|
||||
openssl_public_encrypt($key, $k, $pubkey, $padding);
|
||||
openssl_public_encrypt($iv, $i, $pubkey, $padding);
|
||||
|
||||
$result['alg'] = $alg;
|
||||
$result['key'] = base64url_encode($k, true);
|
||||
$result['iv'] = base64url_encode($i, true);
|
||||
return $result;
|
||||
|
||||
}
|
||||
else {
|
||||
$x = ['data' => $data, 'pubkey' => $pubkey, 'alg' => $alg, 'result' => $data];
|
||||
call_hooks('crypto_encapsulate', $x);
|
||||
return $x['result'];
|
||||
}
|
||||
}
|
||||
|
||||
public static function unencapsulate($data, $prvkey) {
|
||||
|
||||
if (!(is_array($data) && array_key_exists('encrypted', $data) && array_key_exists('alg', $data) && $data['alg'])) {
|
||||
logger('not encrypted');
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
$alg_base = $data['alg'];
|
||||
$padding = OPENSSL_PKCS1_PADDING;
|
||||
|
||||
$exts = explode('.', $data['alg']);
|
||||
if (count($exts) > 1) {
|
||||
switch ($exts[1]) {
|
||||
case 'oaep':
|
||||
$padding = OPENSSL_PKCS1_OAEP_PADDING;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$alg_base = $exts[0];
|
||||
}
|
||||
|
||||
$method = null;
|
||||
|
||||
foreach (self::$openssl_algorithms as $ossl) {
|
||||
if ($ossl[0] === $alg_base) {
|
||||
$method = $ossl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($method) {
|
||||
openssl_private_decrypt(base64url_decode($data['key']), $k, $prvkey, $padding);
|
||||
openssl_private_decrypt(base64url_decode($data['iv']), $i, $prvkey, $padding);
|
||||
return openssl_decrypt(base64url_decode($data['data']), $method[1], substr($k, 0, $method[2]), OPENSSL_RAW_DATA, substr($i, 0, $method[3]));
|
||||
}
|
||||
else {
|
||||
$x = ['data' => $data, 'prvkey' => $prvkey, 'alg' => $data['alg'], 'result' => $data];
|
||||
call_hooks('crypto_unencapsulate', $x);
|
||||
return $x['result'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,8 +87,7 @@ class DReport {
|
||||
|
||||
// Is the sender one of our channels?
|
||||
|
||||
$c = q("select channel_id from channel where channel_hash = '%s' or channel_portable_id = '%s' limit 1",
|
||||
dbesc($dr['sender']),
|
||||
$c = q("select channel_id from channel where channel_hash = '%s' limit 1",
|
||||
dbesc($dr['sender'])
|
||||
);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class Enotify {
|
||||
dbesc($params['to_xchan'])
|
||||
);
|
||||
}
|
||||
if ($x & $y) {
|
||||
if ($x && $y) {
|
||||
$sender = $x[0];
|
||||
$recip = $y[0];
|
||||
} else {
|
||||
@@ -64,29 +64,29 @@ class Enotify {
|
||||
$sitename = get_config('system','sitename');
|
||||
$site_admin = sprintf( t('%s Administrator'), $sitename);
|
||||
$opt_out1 = sprintf( t('This email was sent by %1$s at %2$s.'), t('$Projectname'), \App::get_hostname());
|
||||
$opt_out2 = sprintf( t('To stop receiving these messages, please adjust your Notification Settings at %s'), z_root() . '/settings');
|
||||
$opt_out2 = sprintf( t('To stop receiving these messages, please adjust your Notification Settings at %s'), z_root() . '/settings');
|
||||
$hopt_out2 = sprintf( t('To stop receiving these messages, please adjust your %s.'), '<a href="' . z_root() . '/settings' . '">' . t('Notification Settings') . '</a>');
|
||||
$sender_name = $product;
|
||||
$hostname = \App::get_hostname();
|
||||
if(strpos($hostname,':'))
|
||||
$hostname = substr($hostname,0,strpos($hostname,':'));
|
||||
$hostname = substr($hostname, 0, strpos($hostname,':'));
|
||||
|
||||
// Do not translate 'noreply' as it must be a legal 7-bit email address
|
||||
|
||||
$reply_email = get_config('system','reply_address');
|
||||
$reply_email = get_config('system', 'reply_address');
|
||||
if(! $reply_email)
|
||||
$reply_email = 'noreply' . '@' . $hostname;
|
||||
|
||||
$sender_email = get_config('system','from_email');
|
||||
$sender_email = get_config('system', 'from_email');
|
||||
if(! $sender_email)
|
||||
$sender_email = 'Administrator' . '@' . $hostname;
|
||||
|
||||
$sender_name = get_config('system','from_email_name');
|
||||
|
||||
$sender_name = get_config('system', 'from_email_name');
|
||||
if(! $sender_name)
|
||||
$sender_name = \Zotlabs\Lib\System::get_site_name();
|
||||
|
||||
|
||||
$additional_mail_header = "";
|
||||
$additional_mail_header = '';
|
||||
|
||||
if(array_key_exists('item', $params)) {
|
||||
require_once('include/conversation.php');
|
||||
@@ -108,33 +108,34 @@ class Enotify {
|
||||
logger('notification invoked for an old item which may have been refetched.',LOGGER_DEBUG,LOG_INFO);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$title = $body = '';
|
||||
}
|
||||
|
||||
|
||||
$always_show_in_notices = get_pconfig($recip['channel_id'],'system','always_show_in_notices');
|
||||
$vnotify = get_pconfig($recip['channel_id'],'system','vnotify');
|
||||
$always_show_in_notices = get_pconfig($recip['channel_id'], 'system', 'always_show_in_notices');
|
||||
$vnotify = get_pconfig($recip['channel_id'], 'system', 'vnotify');
|
||||
|
||||
$salutation = $recip['channel_name'];
|
||||
|
||||
// e.g. "your post", "David's photo", etc.
|
||||
$possess_desc = t('%s <!item_type!>');
|
||||
|
||||
// @@TODO: consider using switch instead of those elseif
|
||||
if ($params['type'] == NOTIFY_MAIL) {
|
||||
logger('notification: mail');
|
||||
$subject = sprintf( t('[$Projectname:Notify] New mail received at %s'),$sitename);
|
||||
$subject = sprintf( t('[$Projectname:Notify] New direct message received at %s'), $sitename);
|
||||
|
||||
$preamble = sprintf( t('%1$s sent you a new private message at %2$s.'), $sender['xchan_name'],$sitename);
|
||||
$epreamble = sprintf( t('%1$s sent you %2$s.'),'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', '[zrl=$itemlink]' . t('a private message') . '[/zrl]');
|
||||
$sitelink = t('Please visit %s to view and/or reply to your private messages.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl . '/mail/' . $params['item']['id'] );
|
||||
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/mail/' . $params['item']['id'] . '">' . $sitename . '</a>');
|
||||
$itemlink = $siteurl . '/mail/' . $params['item']['id'];
|
||||
$preamble = sprintf( t('%1$s sent you a new direct message at %2$s.'), $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s sent you %2$s.'), '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', '[zrl=$itemlink]' . t('a direct message') . '[/zrl]');
|
||||
$sitelink = t('Please visit %s to view and/or reply to your direct messages.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl . '/hq/' . gen_link_id($params['item']['mid']));
|
||||
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/hq/' . gen_link_id($params['item']['mid']) . '">' . $sitename . '</a>');
|
||||
$itemlink = $siteurl . '/hq/' . gen_link_id($params['item']['mid']);
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_COMMENT) {
|
||||
elseif ($params['type'] === NOTIFY_COMMENT) {
|
||||
//logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
|
||||
|
||||
$moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false);
|
||||
@@ -143,19 +144,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');
|
||||
|
||||
}
|
||||
|
||||
@@ -164,7 +172,6 @@ class Enotify {
|
||||
// Check to see if there was already a notify for this post.
|
||||
// If so don't create a second notification
|
||||
|
||||
$p = null;
|
||||
$p = q("select id from notify where link = '%s' and uid = %d limit 1",
|
||||
dbesc($params['link']),
|
||||
intval($recip['channel_id'])
|
||||
@@ -174,7 +181,7 @@ class Enotify {
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if it's a post figure out who's post it is.
|
||||
|
||||
@@ -189,6 +196,7 @@ class Enotify {
|
||||
|
||||
xchan_query($p);
|
||||
|
||||
//@@FIXME $p can be null (line 188)
|
||||
$item_post_type = item_post_type($p[0]);
|
||||
// $private = $p[0]['item_private'];
|
||||
$parent_id = $p[0]['id'];
|
||||
@@ -212,7 +220,7 @@ class Enotify {
|
||||
$itemlink,
|
||||
$p[0]['author']['xchan_name'],
|
||||
$item_post_type);
|
||||
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
|
||||
@@ -223,15 +231,15 @@ class Enotify {
|
||||
|
||||
// Some mail softwares relies on subject field for threading.
|
||||
// So, we cannot have different subjects for notifications of the same thread.
|
||||
// Before this we have the name of the replier on the subject rendering
|
||||
// Before this we have the name of the replier on the subject rendering
|
||||
// differents subjects for messages on the same thread.
|
||||
|
||||
if($moderated)
|
||||
$subject = sprintf( t('[$Projectname:Notify] Moderated Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
|
||||
else
|
||||
$subject = sprintf( t('[$Projectname:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
|
||||
$preamble = sprintf( t('%1$s commented on an item/conversation you have been following.'), $sender['xchan_name']);
|
||||
$epreamble = $dest_str;
|
||||
$preamble = sprintf( t('%1$s commented on an item/conversation you have been following.'), $sender['xchan_name']);
|
||||
$epreamble = $dest_str;
|
||||
|
||||
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl );
|
||||
@@ -240,10 +248,10 @@ class Enotify {
|
||||
$tsitelink .= "\n\n" . sprintf( t('Please visit %s to approve or reject this comment.'), z_root() . '/moderate' );
|
||||
$hsitelink .= "<br><br>" . sprintf( t('Please visit %s to approve or reject this comment.'), '<a href="' . z_root() . '/moderate">' . z_root() . '/moderate</a>' );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_LIKE) {
|
||||
elseif ($params['type'] === NOTIFY_LIKE) {
|
||||
// logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
|
||||
|
||||
$itemlink = $params['link'];
|
||||
@@ -261,7 +269,6 @@ class Enotify {
|
||||
// Check to see if there was already a notify for this post.
|
||||
// If so don't create a second notification
|
||||
|
||||
$p = null;
|
||||
$p = q("select id from notify where link = '%s' and uid = %d limit 1",
|
||||
dbesc($params['link']),
|
||||
intval($recip['channel_id'])
|
||||
@@ -271,7 +278,7 @@ class Enotify {
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if it's a post figure out who's post it is.
|
||||
|
||||
@@ -286,7 +293,7 @@ class Enotify {
|
||||
|
||||
xchan_query($p);
|
||||
|
||||
|
||||
//@@FIXME $p can be null (line 285)
|
||||
$item_post_type = item_post_type($p[0]);
|
||||
// $private = $p[0]['item_private'];
|
||||
$parent_id = $p[0]['id'];
|
||||
@@ -295,7 +302,7 @@ class Enotify {
|
||||
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
if($p[0]['owner']['xchan_name'] === $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
$dest_str = sprintf(t('%1$s liked [zrl=%2$s]your %3$s[/zrl]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$itemlink,
|
||||
@@ -307,12 +314,12 @@ class Enotify {
|
||||
|
||||
// Some mail softwares relies on subject field for threading.
|
||||
// So, we cannot have different subjects for notifications of the same thread.
|
||||
// Before this we have the name of the replier on the subject rendering
|
||||
// Before this we have the name of the replier on the subject rendering
|
||||
// differents subjects for messages on the same thread.
|
||||
|
||||
$subject = sprintf( t('[$Projectname:Notify] Like received to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
|
||||
$preamble = sprintf( t('%1$s liked an item/conversation you created.'), $sender['xchan_name']);
|
||||
$epreamble = $dest_str;
|
||||
$preamble = sprintf( t('%1$s liked an item/conversation you created.'), $sender['xchan_name']);
|
||||
$epreamble = $dest_str;
|
||||
|
||||
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl );
|
||||
@@ -321,14 +328,14 @@ class Enotify {
|
||||
|
||||
|
||||
|
||||
if($params['type'] == NOTIFY_WALL) {
|
||||
elseif($params['type'] === NOTIFY_WALL) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] %s posted to your profile wall') , $sender['xchan_name']);
|
||||
|
||||
$preamble = sprintf( t('%1$s posted to your profile wall at %2$s') , $sender['xchan_name'], $sitename);
|
||||
|
||||
$epreamble = sprintf( t('%1$s posted to [zrl=%2$s]your wall[/zrl]') ,
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$params['link']);
|
||||
$params['link']);
|
||||
|
||||
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl );
|
||||
@@ -336,9 +343,8 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_TAGSELF) {
|
||||
elseif ($params['type'] === NOTIFY_TAGSELF) {
|
||||
|
||||
$p = null;
|
||||
$p = q("select id from notify where link = '%s' and uid = %d limit 1",
|
||||
dbesc($params['link']),
|
||||
intval($recip['channel_id'])
|
||||
@@ -348,12 +354,12 @@ class Enotify {
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$subject = sprintf( t('[$Projectname:Notify] %s tagged you') , $sender['xchan_name']);
|
||||
$preamble = sprintf( t('%1$s tagged you at %2$s') , $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s [zrl=%2$s]tagged you[/zrl].') ,
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$params['link']);
|
||||
$params['link']);
|
||||
|
||||
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl );
|
||||
@@ -361,12 +367,12 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_POKE) {
|
||||
elseif ($params['type'] === NOTIFY_POKE) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] %1$s poked you') , $sender['xchan_name']);
|
||||
$preamble = sprintf( t('%1$s poked you at %2$s') , $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s [zrl=%2$s]poked you[/zrl].') ,
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$params['link']);
|
||||
$params['link']);
|
||||
|
||||
$subject = str_replace('poked', t($params['activity']), $subject);
|
||||
$preamble = str_replace('poked', t($params['activity']), $preamble);
|
||||
@@ -378,12 +384,12 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_TAGSHARE) {
|
||||
elseif ($params['type'] === NOTIFY_TAGSHARE) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] %s tagged your post') , $sender['xchan_name']);
|
||||
$preamble = sprintf( t('%1$s tagged your post at %2$s'),$sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s tagged [zrl=%2$s]your post[/zrl]') ,
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$itemlink);
|
||||
$itemlink);
|
||||
|
||||
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
|
||||
$tsitelink = sprintf( $sitelink, $siteurl );
|
||||
@@ -391,12 +397,12 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_INTRO) {
|
||||
elseif ($params['type'] === NOTIFY_INTRO) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] Introduction received'));
|
||||
$preamble = sprintf( t('You\'ve received an new connection request from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$preamble = sprintf( t('You\'ve received an new connection request from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('You\'ve received [zrl=%1$s]a new connection request[/zrl] from %2$s.'),
|
||||
$siteurl . '/connections/ifpending',
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]');
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]');
|
||||
$body = sprintf( t('You may visit their profile at %s'),$sender['xchan_url']);
|
||||
|
||||
$sitelink = t('Please visit %s to approve or reject the connection request.');
|
||||
@@ -405,13 +411,13 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_SUGGEST) {
|
||||
elseif ($params['type'] === NOTIFY_SUGGEST) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] Friend suggestion received'));
|
||||
$preamble = sprintf( t('You\'ve received a friend suggestion from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$preamble = sprintf( t('You\'ve received a friend suggestion from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('You\'ve received [zrl=%1$s]a friend suggestion[/zrl] for %2$s from %3$s.'),
|
||||
$itemlink,
|
||||
'[zrl=' . $params['item']['url'] . ']' . $params['item']['name'] . '[/zrl]',
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]');
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]');
|
||||
|
||||
$body = t('Name:') . ' ' . $params['item']['name'] . "\n";
|
||||
$body .= t('Photo:') . ' ' . $params['item']['photo'] . "\n";
|
||||
@@ -423,11 +429,11 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_CONFIRM) {
|
||||
elseif ($params['type'] === NOTIFY_CONFIRM) {
|
||||
// ?
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_SYSTEM) {
|
||||
elseif ($params['type'] === NOTIFY_SYSTEM) {
|
||||
// ?
|
||||
}
|
||||
|
||||
@@ -455,7 +461,7 @@ class Enotify {
|
||||
$sitelink = $h['sitelink'];
|
||||
$tsitelink = $h['tsitelink'];
|
||||
$hsitelink = $h['hsitelink'];
|
||||
$itemlink = $h['itemlink'];
|
||||
$itemlink = $h['itemlink'];
|
||||
|
||||
|
||||
require_once('include/html2bbcode.php');
|
||||
@@ -470,7 +476,7 @@ class Enotify {
|
||||
} while ($dups === true);
|
||||
|
||||
|
||||
$datarray = array();
|
||||
$datarray = [];
|
||||
$datarray['hash'] = $hash;
|
||||
$datarray['sender_hash'] = $sender['xchan_hash'];
|
||||
$datarray['xname'] = $sender['xchan_name'];
|
||||
@@ -503,11 +509,11 @@ class Enotify {
|
||||
// Mark some notifications as seen right away
|
||||
// Note! The notification have to be created, because they are used to send emails
|
||||
// So easiest solution to hide them from Notices is to mark them as seen right away.
|
||||
// Another option would be to not add them to the DB, and change how emails are handled
|
||||
// Another option would be to not add them to the DB, and change how emails are handled
|
||||
// (probably would be better that way)
|
||||
|
||||
if (!$always_show_in_notices) {
|
||||
if (($params['type'] == NOTIFY_WALL) || ($params['type'] == NOTIFY_MAIL) || ($params['type'] == NOTIFY_INTRO)) {
|
||||
if (($params['type'] === NOTIFY_WALL) || ($params['type'] === NOTIFY_MAIL) || ($params['type'] === NOTIFY_INTRO)) {
|
||||
$seen = 1;
|
||||
}
|
||||
}
|
||||
@@ -543,12 +549,17 @@ class Enotify {
|
||||
}
|
||||
|
||||
$itemlink = z_root() . '/notify/view/' . $notify_id;
|
||||
$msg = str_replace('$itemlink',$itemlink,$epreamble);
|
||||
$msg = str_replace('$itemlink', $itemlink, $epreamble);
|
||||
|
||||
// wretched hack, but we don't want to duplicate all the preamble variations and we also don't want to screw up a translation
|
||||
|
||||
if ((\App::$language === 'en' || (! \App::$language)) && strpos($msg,', '))
|
||||
$msg = substr($msg,strpos($msg,', ')+1);
|
||||
$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),
|
||||
@@ -563,7 +574,7 @@ class Enotify {
|
||||
|
||||
logger('notification: sending notification email');
|
||||
|
||||
$hn = get_pconfig($recip['channel_id'],'system','email_notify_host');
|
||||
$hn = get_pconfig($recip['channel_id'], 'system', 'email_notify_host');
|
||||
if($hn && (! stristr(\App::get_hostname(),$hn))) {
|
||||
// this isn't the email notification host
|
||||
pop_lang();
|
||||
@@ -572,15 +583,15 @@ class Enotify {
|
||||
|
||||
$textversion = strip_tags(html_entity_decode(bbcode(stripslashes(str_replace(array("\\r", "\\n"), array( "", "\n"), $body))),ENT_QUOTES,'UTF-8'));
|
||||
|
||||
$htmlversion = bbcode(stripslashes(str_replace(array("\\r","\\n"), array("","<br />\n"),$body)));
|
||||
$htmlversion = bbcode(stripslashes(str_replace(array("\\r","\\n"), array('',"<br />\n"),$body)));
|
||||
|
||||
|
||||
// use $_SESSION['zid_override'] to force zid() to use
|
||||
// use $_SESSION['zid_override'] to force zid() to use
|
||||
// the recipient address instead of the current observer
|
||||
|
||||
$_SESSION['zid_override'] = channel_reddress($recip);
|
||||
$_SESSION['zrl_override'] = z_root() . '/channel/' . $recip['channel_address'];
|
||||
|
||||
|
||||
$textversion = zidify_links($textversion);
|
||||
$htmlversion = zidify_links($htmlversion);
|
||||
|
||||
@@ -589,7 +600,7 @@ class Enotify {
|
||||
unset($_SESSION['zid_override']);
|
||||
unset($_SESSION['zrl_override']);
|
||||
|
||||
$datarray = array();
|
||||
$datarray = [];
|
||||
$datarray['banner'] = $banner;
|
||||
$datarray['product'] = $product;
|
||||
$datarray['preamble'] = $preamble;
|
||||
@@ -742,21 +753,21 @@ class Enotify {
|
||||
return $params['result'];
|
||||
}
|
||||
|
||||
$fromName = email_header_encode(html_entity_decode($params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
|
||||
$fromName = email_header_encode(html_entity_decode($params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
|
||||
$messageSubject = email_header_encode(html_entity_decode($params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8');
|
||||
|
||||
// generate a mime boundary
|
||||
$mimeBoundary = rand(0, 9) . "-"
|
||||
.rand(100000000, 999999999) . "-"
|
||||
.rand(100000000, 999999999) . "=:"
|
||||
$mimeBoundary = rand(0, 9) . '-'
|
||||
.rand(100000000, 999999999) . '-'
|
||||
.rand(100000000, 999999999) . '=:'
|
||||
.rand(10000, 99999);
|
||||
|
||||
// generate a multipart/alternative message header
|
||||
$messageHeader =
|
||||
$params['additionalMailHeader'] .
|
||||
"From: $fromName <{$params['fromEmail']}>" . PHP_EOL .
|
||||
"Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL .
|
||||
"MIME-Version: 1.0" . 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 +775,15 @@ class Enotify {
|
||||
$htmlBody = chunk_split(base64_encode($params['htmlVersion']));
|
||||
|
||||
$multipartMessageBody =
|
||||
"--" . $mimeBoundary . PHP_EOL . // plain text section
|
||||
"Content-Type: text/plain; charset=UTF-8" . PHP_EOL .
|
||||
"Content-Transfer-Encoding: base64" . PHP_EOL . PHP_EOL .
|
||||
'--' . $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 .
|
||||
'--' . $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
|
||||
'--' . $mimeBoundary . '--' . PHP_EOL; // message ending
|
||||
|
||||
// send the message
|
||||
$res = mail(
|
||||
@@ -781,7 +792,7 @@ class Enotify {
|
||||
$multipartMessageBody, // message body
|
||||
$messageHeader // message headers
|
||||
);
|
||||
logger("notification: enotify::send returns " . (($res) ? 'success' : 'failure'), LOGGER_DEBUG);
|
||||
logger('notification: enotify::send returns ' . (($res) ? 'success' : 'failure'), LOGGER_DEBUG);
|
||||
return $res;
|
||||
}
|
||||
|
||||
@@ -791,7 +802,7 @@ class Enotify {
|
||||
|
||||
require_once('include/conversation.php');
|
||||
|
||||
// Call localize_item to get a one line status for activities.
|
||||
// Call localize_item to get a one line status for activities.
|
||||
// This should set $item['localized'] to indicate we have a brief summary.
|
||||
// and perhaps $item['shortlocalized'] for an even briefer summary
|
||||
|
||||
@@ -805,45 +816,56 @@ 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;
|
||||
|
||||
if($item['edited'] > $item['created']) {
|
||||
$edit = true;
|
||||
if($item['item_thread_top']) {
|
||||
$itemem_text = sprintf( t('edited a post dated %s'), relative_date($item['created']));
|
||||
$edit = true;
|
||||
}
|
||||
else {
|
||||
$itemem_text = sprintf( t('edited a comment dated %s'), relative_date($item['created']));
|
||||
$edit = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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'], ['drop_media', true]), 75, true), ENT_QUOTES, '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
|
||||
);
|
||||
|
||||
call_hooks('enotify_format',$x);
|
||||
call_hooks('enotify_format', $x);
|
||||
if(! $x['display']) {
|
||||
return [];
|
||||
}
|
||||
@@ -851,4 +873,109 @@ 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' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['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) {
|
||||
|
||||
return [
|
||||
'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')
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
static public function format_files($rr) {
|
||||
|
||||
return [
|
||||
'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')
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
static public function format_mail($rr) {
|
||||
|
||||
return [
|
||||
'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 direct message'),
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
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]') : '');
|
||||
|
||||
return [
|
||||
'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')
|
||||
];
|
||||
|
||||
|
||||
}
|
||||
|
||||
static public function format_register($rr) {
|
||||
|
||||
return [
|
||||
'notify_link' => z_root() . '/admin/accounts',
|
||||
'name' => $rr['reg_did2'],
|
||||
//'addr' => '',
|
||||
'photo' => z_root() . '/' . get_default_profile_photo(48),
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(),$rr['reg_created']),
|
||||
'hclass' => ('notify-unseen'),
|
||||
'message' => t('status verified')
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
55
Zotlabs/Lib/Hashpath.php
Normal file
55
Zotlabs/Lib/Hashpath.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
/*
|
||||
* Zotlabs\Lib\Hashpath
|
||||
*
|
||||
* Creates hashed directory structures for fast access and resistance to overloading any single directory with files.
|
||||
*
|
||||
* Takes a $hash which could be any string
|
||||
* a $prefix which is where to place the hash directory in the filesystem, default is current directory
|
||||
* use an empty string for $prefix to place hash directories directly off the root directory
|
||||
* an optional $depth and $slice (default is 2) to indicate the hash level
|
||||
* $depth = 1, 256 directories, suitable for < 384K records/files
|
||||
* $depth = 2, 65536 directories, suitable for < 98M records/files
|
||||
* $depth = 3, 16777216 directories, suitable for < 2.5B records/files
|
||||
* ...
|
||||
* The total number of records anticipated divided by the number of hash directories should generally be kept to
|
||||
* less than 1500 entries for optimum performance though this varies by operating system and filesystem type.
|
||||
* ext4 uses 32 bit inode numbers (~4B record limit) so use caution or alternative filesystem types with $depth above 3.
|
||||
* an optional $mkdir (boolean) to recursively create the directory (ignoring errors) before returning
|
||||
*
|
||||
* examples: for a $hash of 'abcdefg' and prefix of 'path' the following paths are returned for $depth = 1 and $depth = 3
|
||||
* path/7d/7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a
|
||||
* path/7d/1a/54/7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a
|
||||
*
|
||||
* see also: boot.php:os_mkdir() - here we provide the equivalent of mkdir -p with permissions of 770.
|
||||
*
|
||||
*/
|
||||
|
||||
class Hashpath {
|
||||
|
||||
static function path($hash, $prefix = '.', $depth = 1, $slice = 2, $mkdir = true, $alg = false) {
|
||||
|
||||
if ($alg)
|
||||
$hash = hash($alg, $hash);
|
||||
|
||||
$start = 0;
|
||||
if ($depth < 1)
|
||||
$depth = 1;
|
||||
$sluglen = $depth * $slice;
|
||||
|
||||
do {
|
||||
$slug = substr($hash, $start, $slice);
|
||||
$prefix .= '/' . $slug;
|
||||
$start += $slice;
|
||||
$sluglen -= $slice;
|
||||
}
|
||||
while ($sluglen);
|
||||
|
||||
if ($mkdir)
|
||||
os_mkdir($prefix, STORAGE_DEFAULT_PERMISSIONS, true);
|
||||
|
||||
return $prefix . '/' . $hash;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
class JSalmon {
|
||||
|
||||
@@ -18,7 +18,7 @@ class JSalmon {
|
||||
|
||||
$precomputed = '.' . base64url_encode($data_type,true) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng';
|
||||
|
||||
$signature = base64url_encode(rsa_sign($data . $precomputed, $key), true);
|
||||
$signature = base64url_encode(Crypto::sign($data . $precomputed, $key), true);
|
||||
|
||||
return ([
|
||||
'signed' => true,
|
||||
@@ -40,21 +40,21 @@ class JSalmon {
|
||||
$ret = [ 'results' => [] ];
|
||||
|
||||
if(! is_array($x)) {
|
||||
return $false;
|
||||
return false;
|
||||
}
|
||||
if(! ( array_key_exists('signed',$x) && $x['signed'])) {
|
||||
return $false;
|
||||
return false;
|
||||
}
|
||||
|
||||
$signed_data = preg_replace('/\s+/','',$x['data']) . '.'
|
||||
. base64url_encode($x['data_type'],true) . '.'
|
||||
. base64url_encode($x['encoding'],true) . '.'
|
||||
$signed_data = preg_replace('/\s+/','',$x['data']) . '.'
|
||||
. base64url_encode($x['data_type'],true) . '.'
|
||||
. 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'])) {
|
||||
if(Crypto::verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {
|
||||
logger('verified');
|
||||
$ret = [ 'success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc'] ];
|
||||
}
|
||||
@@ -69,4 +69,4 @@ class JSalmon {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
99
Zotlabs/Lib/Keyutils.php
Normal file
99
Zotlabs/Lib/Keyutils.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* Keyutils
|
||||
* Convert RSA keys between various formats
|
||||
*/
|
||||
class Keyutils {
|
||||
|
||||
/**
|
||||
* @param string $m modulo
|
||||
* @param string $e exponent
|
||||
* @return string
|
||||
*/
|
||||
public static function meToPem($m, $e) {
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey([
|
||||
'e' => new BigInteger($e, 256),
|
||||
'n' => new BigInteger($m, 256)
|
||||
]);
|
||||
return $rsa->getPublicKey();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string key
|
||||
* @return string
|
||||
*/
|
||||
public static function rsaToPem($key) {
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setPublicKey($key);
|
||||
|
||||
return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS8);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string key
|
||||
* @return string
|
||||
*/
|
||||
public static function pemToRsa($key) {
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setPublicKey($key);
|
||||
|
||||
return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key key
|
||||
* @param string $m reference modulo
|
||||
* @param string $e reference exponent
|
||||
*/
|
||||
public static function pemToMe($key, &$m, &$e) {
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey($key);
|
||||
$rsa->setPublicKey();
|
||||
|
||||
$m = $rsa->modulus->toBytes();
|
||||
$e = $rsa->exponent->toBytes();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pubkey
|
||||
* @return string
|
||||
*/
|
||||
public static function salmonKey($pubkey) {
|
||||
self::pemToMe($pubkey, $m, $e);
|
||||
return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
public static function convertSalmonKey($key) {
|
||||
if (strstr($key, ','))
|
||||
$rawkey = substr($key, strpos($key, ',') + 1);
|
||||
else
|
||||
$rawkey = substr($key, 5);
|
||||
|
||||
$key_info = explode('.', $rawkey);
|
||||
|
||||
$m = base64url_decode($key_info[1]);
|
||||
$e = base64url_decode($key_info[2]);
|
||||
|
||||
return self::meToPem($m, $e);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@ class LDSignatures {
|
||||
$ohash = self::hash(self::signable_options($data['signature']));
|
||||
$dhash = self::hash(self::signable_data($data));
|
||||
|
||||
$x = rsa_verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey);
|
||||
$x = Crypto::verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey);
|
||||
logger('LD-verify: ' . intval($x));
|
||||
|
||||
return $x;
|
||||
@@ -29,17 +29,17 @@ 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));
|
||||
$dhash = self::hash(self::signable_data($data));
|
||||
$options['signatureValue'] = base64_encode(rsa_sign($ohash . $dhash,$channel['channel_prvkey']));
|
||||
$options['signatureValue'] = base64_encode(Crypto::sign($ohash . $dhash,$channel['channel_prvkey']));
|
||||
|
||||
$signed = array_merge([
|
||||
'@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1' ],
|
||||
],$options);
|
||||
|
||||
@@ -88,12 +88,13 @@ class LDSignatures {
|
||||
return '';
|
||||
|
||||
jsonld_set_document_loader('jsonld_document_loader');
|
||||
|
||||
|
||||
try {
|
||||
$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));
|
||||
}
|
||||
|
||||
@@ -116,7 +117,7 @@ class LDSignatures {
|
||||
|
||||
$precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
|
||||
|
||||
$signature = base64url_encode(rsa_sign($data . $precomputed,$channel['channel_prvkey']));
|
||||
$signature = base64url_encode(Crypto::sign($data . $precomputed,$channel['channel_prvkey']));
|
||||
|
||||
return ([
|
||||
'id' => $arr['id'],
|
||||
@@ -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 {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,8 @@
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
use Zotlabs\Lib\Webfinger;
|
||||
|
||||
require_once('include/permissions.php');
|
||||
|
||||
@@ -17,7 +19,6 @@ class Libzotdir {
|
||||
*/
|
||||
|
||||
static function find_upstream_directory($dirmode) {
|
||||
global $DIRECTORY_FALLBACK_SERVERS;
|
||||
|
||||
$preferred = get_config('system','directory_server');
|
||||
|
||||
@@ -29,7 +30,7 @@ class Libzotdir {
|
||||
);
|
||||
if(($r) && ($r[0]['site_flags'] & DIRECTORY_MODE_STANDALONE)) {
|
||||
$preferred = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,19 +41,21 @@ class Libzotdir {
|
||||
* from our list of directory servers. However, if we're a directory
|
||||
* server ourself, point at the local instance
|
||||
* We will then set this value so this should only ever happen once.
|
||||
* Ideally there will be an admin setting to change to a different
|
||||
* Ideally there will be an admin setting to change to a different
|
||||
* directory server if you don't like our choice or if circumstances change.
|
||||
*/
|
||||
|
||||
$directory_fallback_servers = get_directory_fallback_servers();
|
||||
|
||||
$dirmode = intval(get_config('system','directory_mode'));
|
||||
if ($dirmode == DIRECTORY_MODE_NORMAL) {
|
||||
$toss = mt_rand(0,count($DIRECTORY_FALLBACK_SERVERS));
|
||||
$preferred = $DIRECTORY_FALLBACK_SERVERS[$toss];
|
||||
$toss = mt_rand(0,count($directory_fallback_servers));
|
||||
$preferred = $directory_fallback_servers[$toss];
|
||||
if(! $preferred) {
|
||||
$preferred = DIRECTORY_FALLBACK_MASTER;
|
||||
}
|
||||
set_config('system','directory_server',$preferred);
|
||||
}
|
||||
}
|
||||
else {
|
||||
set_config('system','directory_server',z_root());
|
||||
}
|
||||
@@ -106,7 +109,7 @@ class Libzotdir {
|
||||
$ret = get_config('directory', $setting);
|
||||
|
||||
|
||||
// 'safemode' is the default if there is no observer or no established preference.
|
||||
// 'safemode' is the default if there is no observer or no established preference.
|
||||
|
||||
if($setting === 'safemode' && $ret === false)
|
||||
$ret = 1;
|
||||
@@ -173,8 +176,8 @@ class Libzotdir {
|
||||
*
|
||||
* Checks the directory mode of this hub to see if it is some form of directory server. If it is,
|
||||
* get the directory realm of this hub. Fetch a list of all other directory servers in this realm and request
|
||||
* a directory sync packet. This will contain both directory updates and new ratings. Store these all in the DB.
|
||||
* In the case of updates, we will query each of them asynchronously from a poller task. Ratings are stored
|
||||
* a directory sync packet. This will contain both directory updates and new ratings. Store these all in the DB.
|
||||
* In the case of updates, we will query each of them asynchronously from a poller task. Ratings are stored
|
||||
* directly if the rater's signature matches.
|
||||
*
|
||||
* @param int $dirmode;
|
||||
@@ -186,16 +189,17 @@ class Libzotdir {
|
||||
return;
|
||||
|
||||
$realm = get_directory_realm();
|
||||
|
||||
if ($realm == DIRECTORY_REALM) {
|
||||
$r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_type = %d and ( site_realm = '%s' or site_realm = '') ",
|
||||
$r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_type = %d and ( site_realm = '%s' or site_realm = '') and site_dead = 0",
|
||||
intval(DIRECTORY_MODE_PRIMARY|DIRECTORY_MODE_SECONDARY),
|
||||
dbesc(z_root()),
|
||||
intval(SITE_TYPE_ZOT),
|
||||
dbesc($realm)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_realm like '%s' and site_type = %d ",
|
||||
$r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_realm like '%s' and site_type = %d and site_dead = 0",
|
||||
intval(DIRECTORY_MODE_PRIMARY|DIRECTORY_MODE_SECONDARY),
|
||||
dbesc(z_root()),
|
||||
dbesc(protect_sprintf('%' . $realm . '%')),
|
||||
@@ -212,14 +216,14 @@ class Libzotdir {
|
||||
[
|
||||
'site_url' => DIRECTORY_FALLBACK_MASTER,
|
||||
'site_flags' => DIRECTORY_MODE_PRIMARY,
|
||||
'site_update' => NULL_DATE,
|
||||
'site_update' => NULL_DATE,
|
||||
'site_directory' => DIRECTORY_FALLBACK_MASTER . '/dirsearch',
|
||||
'site_realm' => DIRECTORY_REALM,
|
||||
'site_valid' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$r = q("select * from site where site_flags in (%d, %d) and site_url != '%s' and site_type = %d ",
|
||||
$r = q("select * from site where site_flags in (%d, %d) and site_url != '%s' and site_type = %d and site_dead = 0",
|
||||
intval(DIRECTORY_MODE_PRIMARY),
|
||||
intval(DIRECTORY_MODE_SECONDARY),
|
||||
dbesc(z_root()),
|
||||
@@ -248,7 +252,7 @@ class Libzotdir {
|
||||
continue;
|
||||
|
||||
$j = json_decode($x['body'],true);
|
||||
if (!($j['transactions']) || ($j['ratings']))
|
||||
if (!$j['transactions'])
|
||||
continue;
|
||||
|
||||
q("update site set site_sync = '%s' where site_url = '%s'",
|
||||
@@ -260,6 +264,11 @@ class Libzotdir {
|
||||
|
||||
if (is_array($j['transactions']) && count($j['transactions'])) {
|
||||
foreach ($j['transactions'] as $t) {
|
||||
|
||||
if (empty($t['hash']) || empty($t['transaction_id']) || empty($t['address'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$r = q("select * from updates where ud_guid = '%s' limit 1",
|
||||
dbesc($t['transaction_id'])
|
||||
);
|
||||
@@ -271,7 +280,7 @@ class Libzotdir {
|
||||
$ud_flags |= UPDATE_FLAGS_DELETED;
|
||||
if (is_array($t['flags']) && in_array('forced',$t['flags']))
|
||||
$ud_flags |= UPDATE_FLAGS_FORCED;
|
||||
|
||||
|
||||
$z = q("insert into updates ( ud_hash, ud_guid, ud_date, ud_flags, ud_addr )
|
||||
values ( '%s', '%s', '%s', %d, '%s' ) ",
|
||||
dbesc($t['hash']),
|
||||
@@ -306,13 +315,22 @@ class Libzotdir {
|
||||
|
||||
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
|
||||
$success = false;
|
||||
$zf = [];
|
||||
|
||||
$href = \Zotlabs\Lib\Webfinger::zot_url(punify($ud['ud_addr']));
|
||||
$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'])) {
|
||||
if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
|
||||
$xc = Libzot::import_xchan($zf['data'], 0, $ud);
|
||||
// This is a workaround for a missing xchan_updated column
|
||||
// TODO: implement xchan_updated in the xchan table and update this column instead
|
||||
if($zf['data']['primary_location']['address'] && $zf['data']['primary_location']['url']) {
|
||||
q("UPDATE hubloc SET hubloc_updated = '%s' WHERE hubloc_id_url = '%s' AND hubloc_primary = 1",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($zf['data']['primary_location']['url'])
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
q("update updates set ud_last = '%s' where ud_addr = '%s'",
|
||||
@@ -336,7 +354,7 @@ class Libzotdir {
|
||||
|
||||
static function local_dir_update($uid, $force) {
|
||||
|
||||
|
||||
|
||||
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",
|
||||
@@ -351,7 +369,7 @@ class Libzotdir {
|
||||
|
||||
$profile['description'] = $p[0]['pdesc'];
|
||||
$profile['birthday'] = $p[0]['dob'];
|
||||
if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],''))
|
||||
if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],''))
|
||||
$profile['age'] = $age;
|
||||
|
||||
$profile['gender'] = $p[0]['gender'];
|
||||
@@ -381,14 +399,14 @@ 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'",
|
||||
intval($hidden),
|
||||
dbesc($p[0]['channel_hash'])
|
||||
dbesc($hash)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -402,14 +420,14 @@ class Libzotdir {
|
||||
}
|
||||
else {
|
||||
// they may have made it private
|
||||
$r = q("delete from xprof where xprof_hash = '%s'",
|
||||
q("delete from xprof where xprof_hash = '%s'",
|
||||
dbesc($hash)
|
||||
);
|
||||
$r = q("delete from xtag where xtag_hash = '%s'",
|
||||
q("delete from xtag where xtag_hash = '%s'",
|
||||
dbesc($hash)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
$ud_hash = random_string() . '@' . \App::get_hostname();
|
||||
@@ -440,7 +458,7 @@ class Libzotdir {
|
||||
$arr['xprof_hash'] = $hash;
|
||||
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('','',$profile['birthday'],'Y-m-d')); // !!!! check this for 0000 year
|
||||
$arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0);
|
||||
$arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_gender'] = (($profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_marital'] = (($profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_sexual'] = (($profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
@@ -625,8 +643,13 @@ class Libzotdir {
|
||||
|
||||
$dirmode = intval(get_config('system', 'directory_mode'));
|
||||
|
||||
if($dirmode == DIRECTORY_MODE_NORMAL)
|
||||
if($dirmode == DIRECTORY_MODE_NORMAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($hash) || empty($guid) || empty($addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if($flags) {
|
||||
q("insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )",
|
||||
@@ -635,7 +658,7 @@ class Libzotdir {
|
||||
dbesc(datetime_convert()),
|
||||
intval($flags),
|
||||
dbesc($addr)
|
||||
);
|
||||
);
|
||||
}
|
||||
else {
|
||||
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d)>0 ",
|
||||
@@ -646,9 +669,4 @@ class Libzotdir {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@ class MessageFilter {
|
||||
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
unobscure($item);
|
||||
|
||||
$text = prepare_text($item['body'],$item['mimetype']);
|
||||
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
|
||||
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
define ( 'NWIKI_ITEM_RESOURCE_TYPE', 'nwiki' );
|
||||
|
||||
class NativeWiki {
|
||||
|
||||
|
||||
static public function listwikis($channel, $observer_hash) {
|
||||
public static function listwikis($channel, $observer_hash) {
|
||||
|
||||
$sql_extra = item_permissions_sql($channel['channel_id'], $observer_hash);
|
||||
$wikis = q("SELECT * FROM item
|
||||
@@ -38,7 +40,7 @@ class NativeWiki {
|
||||
}
|
||||
|
||||
|
||||
function create_wiki($channel, $observer_hash, $wiki, $acl) {
|
||||
public static function create_wiki($channel, $observer_hash, $wiki, $acl) {
|
||||
|
||||
$resource_id = new_uuid();
|
||||
$uuid = new_uuid();
|
||||
@@ -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);
|
||||
@@ -99,7 +101,8 @@ class NativeWiki {
|
||||
}
|
||||
}
|
||||
|
||||
function update_wiki($channel_id, $observer_hash, $arr, $acl) {
|
||||
|
||||
public static function update_wiki($channel_id, $observer_hash, $arr, $acl) {
|
||||
|
||||
$w = self::get_wiki($channel_id, $observer_hash, $arr['resource_id']);
|
||||
$item = $w['wiki'];
|
||||
@@ -154,8 +157,8 @@ class NativeWiki {
|
||||
}
|
||||
}
|
||||
|
||||
static public function sync_a_wiki_item($uid,$id,$resource_id) {
|
||||
|
||||
public static function sync_a_wiki_item($uid,$id,$resource_id) {
|
||||
|
||||
$r = q("SELECT * from item WHERE uid = %d AND ( id = %d OR ( resource_type = '%s' and resource_id = '%s' )) ",
|
||||
intval($uid),
|
||||
@@ -163,8 +166,8 @@ class NativeWiki {
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
|
||||
$q = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s'",
|
||||
dbesc($r[0]['resource_id'])
|
||||
);
|
||||
@@ -178,40 +181,47 @@ 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function delete_wiki($channel_id,$observer_hash,$resource_id) {
|
||||
|
||||
public static function delete_wiki($channel_id,$observer_hash,$resource_id) {
|
||||
|
||||
$w = self::get_wiki($channel_id,$observer_hash,$resource_id);
|
||||
$item = $w['wiki'];
|
||||
if(! $item) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
else {
|
||||
$drop = drop_item($item['id'], false, DROPITEM_NORMAL);
|
||||
if(! $w['wiki']) {
|
||||
return [ 'success' => false ];
|
||||
}
|
||||
else {
|
||||
|
||||
info( t('Wiki files deleted successfully'));
|
||||
$r = q("SELECT id FROM item WHERE uid = %s AND resource_id = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
|
||||
return array('item' => $item, 'item_id' => $item['id'], 'success' => (($drop === 1) ? true : false));
|
||||
$ids = array_column($r, 'id');
|
||||
drop_items($ids, true, DROPITEM_PHASE1);
|
||||
|
||||
info(t('Wiki files deleted successfully'));
|
||||
|
||||
return [ 'success' => true ];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public function get_wiki($channel_id, $observer_hash, $resource_id) {
|
||||
public static function get_wiki($channel_id, $observer_hash, $resource_id) {
|
||||
|
||||
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
|
||||
|
||||
$item = q("SELECT * FROM item WHERE uid = %d AND resource_type = '%s' AND resource_id = '%s' AND item_deleted = 0
|
||||
$sql_extra limit 1",
|
||||
$sql_extra ORDER BY id LIMIT 1",
|
||||
intval($channel_id),
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
if(! $item) {
|
||||
return array('wiki' => null);
|
||||
return [ 'wiki' => null ];
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -234,7 +244,7 @@ class NativeWiki {
|
||||
}
|
||||
|
||||
|
||||
static public function exists_by_name($uid, $urlName) {
|
||||
public static function exists_by_name($uid, $urlName) {
|
||||
|
||||
$sql_extra = item_permissions_sql($uid);
|
||||
|
||||
@@ -256,7 +266,8 @@ class NativeWiki {
|
||||
}
|
||||
|
||||
|
||||
static public function get_permissions($resource_id, $owner_id, $observer_hash) {
|
||||
public static function get_permissions($resource_id, $owner_id, $observer_hash) {
|
||||
|
||||
// TODO: For now, only the owner can edit
|
||||
$sql_extra = item_permissions_sql($owner_id, $observer_hash);
|
||||
|
||||
@@ -281,6 +292,7 @@ class NativeWiki {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function name_encode ($string) {
|
||||
|
||||
$string = html_entity_decode($string);
|
||||
@@ -296,6 +308,7 @@ class NativeWiki {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
public static function name_decode ($string) {
|
||||
|
||||
$encoding = mb_internal_encoding();
|
||||
|
||||
@@ -109,6 +109,7 @@ class NativeWikiPage {
|
||||
return [ 'success' => false, 'message' => t('Wiki page create failed.') ];
|
||||
}
|
||||
|
||||
|
||||
static public function rename_page($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
@@ -163,11 +164,13 @@ class NativeWikiPage {
|
||||
return [ 'success' => true, 'page' => $page ];
|
||||
}
|
||||
|
||||
return [ 'success' => false, 'item_id' => $c['item_id'], 'message' => t('Page not found') ];
|
||||
return [ 'success' => false, 'message' => t('Page not found') ];
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function get_page_content($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
@@ -198,7 +201,9 @@ class NativeWikiPage {
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function page_history($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
@@ -290,6 +295,7 @@ class NativeWikiPage {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static public function load_page_history($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
@@ -338,8 +344,8 @@ class NativeWikiPage {
|
||||
return null;
|
||||
}
|
||||
|
||||
static public function save_page($arr) {
|
||||
|
||||
static public function save_page($arr) {
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$content = ((array_key_exists('content',$arr)) ? $arr['content'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
@@ -385,19 +391,20 @@ class NativeWikiPage {
|
||||
$ret = item_store($item, false, false);
|
||||
|
||||
if($ret['item_id'])
|
||||
return array('message' => '', 'item_id' => $ret['item_id'], 'filename' => $filename, 'success' => true);
|
||||
return array('message' => '', 'item_id' => $ret['item_id'], 'filename' => $pageUrlName, 'success' => true);
|
||||
else
|
||||
return array('message' => t('Page update failed.'), 'success' => false);
|
||||
}
|
||||
|
||||
|
||||
static public function delete_page($arr) {
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
$pageUrlName = (array_key_exists('pageUrlName',$arr) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = (array_key_exists('resource_id',$arr) ? $arr['resource_id'] : '');
|
||||
$observer_hash = (array_key_exists('observer_hash',$arr) ? $arr['observer_hash'] : '');
|
||||
$channel_id = (array_key_exists('channel_id',$arr) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if(! $w['wiki']) {
|
||||
return [ 'success' => false, 'message' => t('Error reading wiki') ];
|
||||
}
|
||||
@@ -417,14 +424,16 @@ class NativeWikiPage {
|
||||
}
|
||||
|
||||
if($ids) {
|
||||
drop_items($ids);
|
||||
drop_items($ids, true, DROPITEM_PHASE1);
|
||||
return [ 'success' => true ];
|
||||
}
|
||||
|
||||
return [ 'success' => false, 'message' => t('Nothing deleted') ];
|
||||
}
|
||||
|
||||
|
||||
static public function revert_page($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$commitHash = ((array_key_exists('commitHash',$arr)) ? $arr['commitHash'] : null);
|
||||
@@ -432,12 +441,12 @@ class NativeWikiPage {
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
if (! $commitHash) {
|
||||
return array('content' => $content, 'message' => 'No commit was provided', 'success' => false);
|
||||
return array('message' => 'No commit was provided', 'success' => false);
|
||||
}
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (!$w['wiki']) {
|
||||
return array('content' => $content, 'message' => 'Error reading wiki', 'success' => false);
|
||||
return array('message' => 'Error reading wiki', 'success' => false);
|
||||
}
|
||||
|
||||
$x = $arr;
|
||||
@@ -451,11 +460,13 @@ class NativeWikiPage {
|
||||
$content = $loaded['body'];
|
||||
return [ 'content' => $content, 'success' => true ];
|
||||
}
|
||||
return [ 'content' => $content, 'success' => false ];
|
||||
return [ 'success' => false ];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public function compare_page($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$currentCommit = ((array_key_exists('currentCommit',$arr)) ? $arr['currentCommit'] : (-1));
|
||||
@@ -491,6 +502,7 @@ class NativeWikiPage {
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function commit($arr) {
|
||||
|
||||
$commit_msg = ((array_key_exists('commit_msg', $arr)) ? $arr['commit_msg'] : t('Page updated'));
|
||||
@@ -530,8 +542,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) {
|
||||
@@ -568,7 +583,6 @@ class NativeWikiPage {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Replace the instances of the string [toc] with a list element that will be populated by
|
||||
* a table of contents by the JavaScript library
|
||||
@@ -584,6 +598,7 @@ class NativeWikiPage {
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a select set of bbcode tags. Much of the code is copied from include/bbcode.php
|
||||
* @param string $s
|
||||
@@ -623,7 +638,9 @@ class NativeWikiPage {
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
static public function get_file_ext($arr) {
|
||||
|
||||
if($arr['mimetype'] === 'text/bbcode')
|
||||
return '.bb';
|
||||
elseif($arr['mimetype'] === 'text/markdown')
|
||||
|
||||
@@ -132,6 +132,7 @@ class PConfig {
|
||||
// manage array value
|
||||
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
|
||||
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
|
||||
$new = false;
|
||||
|
||||
$now = datetime_convert();
|
||||
if (! $updated) {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
use Zotlabs\Zot6\Receiver;
|
||||
use Zotlabs\Zot6\Zot6Handler;
|
||||
|
||||
class Queue {
|
||||
|
||||
@@ -31,19 +31,19 @@ class Queue {
|
||||
$might_be_down = ((datetime_convert('UTC','UTC',$y[0]['earliest']) < datetime_convert('UTC','UTC','now - 2 days')) ? true : false);
|
||||
|
||||
|
||||
// Set all other records for this destination way into the future.
|
||||
// Set all other records for this destination way into the future.
|
||||
// The queue delivers by destination. We'll keep one queue item for
|
||||
// this destination (this one) with a shorter delivery. If we succeed
|
||||
// once, we'll try to deliver everything for that destination.
|
||||
// The delivery will be set to at most once per hour, and if the
|
||||
// The delivery will be set to at most once per hour, and if the
|
||||
// queue item is less than 12 hours old, we'll schedule for fifteen
|
||||
// minutes.
|
||||
// minutes.
|
||||
|
||||
$r = q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_posturl = '%s'",
|
||||
q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_posturl = '%s'",
|
||||
dbesc(datetime_convert('UTC','UTC','now + 5 days')),
|
||||
dbesc($x[0]['outq_posturl'])
|
||||
);
|
||||
|
||||
|
||||
$since = datetime_convert('UTC','UTC',$x[0]['outq_created']);
|
||||
|
||||
if(($might_be_down) || ($since < datetime_convert('UTC','UTC','now - 12 hour'))) {
|
||||
@@ -53,9 +53,9 @@ class Queue {
|
||||
$next = datetime_convert('UTC','UTC','now + ' . intval($add_priority) . ' minutes');
|
||||
}
|
||||
|
||||
q("UPDATE outq SET outq_updated = '%s',
|
||||
outq_priority = outq_priority + %d,
|
||||
outq_scheduled = '%s'
|
||||
q("UPDATE outq SET outq_updated = '%s',
|
||||
outq_priority = outq_priority + %d,
|
||||
outq_scheduled = '%s'
|
||||
WHERE outq_hash = '%s'",
|
||||
|
||||
dbesc(datetime_convert()),
|
||||
@@ -69,7 +69,7 @@ class Queue {
|
||||
static function remove($id,$channel_id = 0) {
|
||||
logger('queue: remove queue item ' . $id,LOGGER_DEBUG);
|
||||
$sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : '');
|
||||
|
||||
|
||||
q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra",
|
||||
dbesc($id)
|
||||
);
|
||||
@@ -78,7 +78,7 @@ class Queue {
|
||||
|
||||
static function remove_by_posturl($posturl) {
|
||||
logger('queue: remove queue posturl ' . $posturl,LOGGER_DEBUG);
|
||||
|
||||
|
||||
q("DELETE FROM outq WHERE outq_posturl = '%s' ",
|
||||
dbesc($posturl)
|
||||
);
|
||||
@@ -88,10 +88,10 @@ class Queue {
|
||||
|
||||
static function set_delivered($id,$channel = 0) {
|
||||
logger('queue: set delivered ' . $id,LOGGER_DEBUG);
|
||||
$sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : '');
|
||||
$sql_extra = (($channel['channel_id']) ? " and outq_channel = " . intval($channel['channel_id']) . " " : '');
|
||||
|
||||
// Set the next scheduled run date so far in the future that it will be expired
|
||||
// long before it ever makes it back into the delivery chain.
|
||||
// long before it ever makes it back into the delivery chain.
|
||||
|
||||
q("update outq set outq_delivered = 1, outq_updated = '%s', outq_scheduled = '%s' where outq_hash = '%s' $sql_extra ",
|
||||
dbesc(datetime_convert()),
|
||||
@@ -111,15 +111,15 @@ class Queue {
|
||||
}
|
||||
|
||||
$x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority,
|
||||
outq_created, outq_updated, outq_scheduled, outq_notify, outq_msg )
|
||||
outq_created, outq_updated, outq_scheduled, outq_notify, outq_msg )
|
||||
values ( '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s' )",
|
||||
dbesc($arr['hash']),
|
||||
intval($arr['account_id']),
|
||||
intval($arr['channel_id']),
|
||||
dbesc(($arr['driver']) ? $arr['driver'] : 'zot'),
|
||||
dbesc(($arr['driver']) ? $arr['driver'] : 'zot6'),
|
||||
dbesc($arr['posturl']),
|
||||
intval(1),
|
||||
intval(($arr['priority']) ? $arr['priority'] : 0),
|
||||
intval(isset($arr['priority']) ? $arr['priority'] : 0),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
@@ -136,8 +136,8 @@ class Queue {
|
||||
|
||||
$base = null;
|
||||
$h = parse_url($outq['outq_posturl']);
|
||||
if($h !== false)
|
||||
$base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
|
||||
if($h !== false)
|
||||
$base = $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : '');
|
||||
|
||||
if(($base) && ($base !== z_root()) && ($immediate)) {
|
||||
$y = q("select site_update, site_dead from site where site_url = '%s' ",
|
||||
@@ -150,7 +150,7 @@ class Queue {
|
||||
return;
|
||||
}
|
||||
if($y[0]['site_update'] < datetime_convert('UTC','UTC','now - 1 month')) {
|
||||
self::update($outq['outq_hash'],10);
|
||||
self::update($outq['outq_hash'], 10);
|
||||
logger('immediate delivery deferred for site ' . $base);
|
||||
return;
|
||||
}
|
||||
@@ -161,12 +161,12 @@ class Queue {
|
||||
// your site has existed. Since we don't know for sure what these sites are,
|
||||
// call them unknown
|
||||
|
||||
site_store_lowlevel(
|
||||
site_store_lowlevel(
|
||||
[
|
||||
'site_url' => $base,
|
||||
'site_update' => datetime_convert(),
|
||||
'site_dead' => 0,
|
||||
'site_type' => intval(($outq['outq_driver'] === 'post') ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN),
|
||||
'site_type' => SITE_TYPE_UNKNOWN,
|
||||
'site_crypto' => ''
|
||||
]
|
||||
);
|
||||
@@ -174,67 +174,18 @@ class Queue {
|
||||
}
|
||||
|
||||
$arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
|
||||
call_hooks('queue_deliver',$arr);
|
||||
call_hooks('queue_deliver', $arr);
|
||||
if($arr['handled'])
|
||||
return;
|
||||
|
||||
// "post" queue driver - used for diaspora and friendica-over-diaspora communications.
|
||||
|
||||
if($outq['outq_driver'] === 'post') {
|
||||
$result = z_post_url($outq['outq_posturl'],$outq['outq_msg']);
|
||||
if($result['success'] && $result['return_code'] < 300) {
|
||||
logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
|
||||
if($base) {
|
||||
q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($base)
|
||||
);
|
||||
}
|
||||
q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
|
||||
dbesc('accepted for delivery'),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($outq['outq_hash'])
|
||||
);
|
||||
self::remove($outq['outq_hash']);
|
||||
|
||||
// server is responding - see if anything else is going to this destination and is piled up
|
||||
// and try to send some more. We're relying on the fact that do_delivery() results in an
|
||||
// immediate delivery otherwise we could get into a queue loop.
|
||||
|
||||
if(! $immediate) {
|
||||
$x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0",
|
||||
dbesc($outq['outq_posturl'])
|
||||
);
|
||||
|
||||
$piled_up = array();
|
||||
if($x) {
|
||||
foreach($x as $xx) {
|
||||
$piled_up[] = $xx['outq_hash'];
|
||||
}
|
||||
}
|
||||
if($piled_up) {
|
||||
// call do_delivery() with the force flag
|
||||
do_delivery($piled_up, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger('deliver: queue post returned ' . $result['return_code']
|
||||
. ' from ' . $outq['outq_posturl'],LOGGER_DEBUG);
|
||||
self::update($outq['outq_hash'],10);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// normal zot delivery
|
||||
|
||||
logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
|
||||
|
||||
|
||||
if($outq['outq_posturl'] === z_root() . '/zot') {
|
||||
// local delivery
|
||||
$zot = new \Zotlabs\Zot6\Receiver(new \Zotlabs\Zot6\Zot6Handler(),$outq['outq_notify']);
|
||||
$result = $zot->run(true);
|
||||
$zot = new Receiver(new Zot6Handler(), $outq['outq_notify']);
|
||||
$result = $zot->run();
|
||||
logger('returned_json: ' . json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DATA);
|
||||
logger('deliver: local zot delivery succeeded to ' . $outq['outq_posturl']);
|
||||
Libzot::process_response($outq['outq_posturl'],[ 'success' => true, 'body' => json_encode($result) ], $outq);
|
||||
@@ -250,7 +201,8 @@ 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_network = 'zot6' ORDER BY hubloc_id DESC LIMIT 1",
|
||||
dbesc($base)
|
||||
);
|
||||
if($h) {
|
||||
@@ -260,7 +212,7 @@ class Queue {
|
||||
|
||||
$msg = $outq['outq_notify'];
|
||||
|
||||
$result = Libzot::zot($outq['outq_posturl'],$msg,$channel,$host_crypto);
|
||||
$result = Libzot::zot($outq['outq_posturl'], $msg, $channel, $host_crypto);
|
||||
|
||||
if($result['success']) {
|
||||
logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']);
|
||||
@@ -269,7 +221,7 @@ class Queue {
|
||||
else {
|
||||
logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']);
|
||||
logger('deliver: remote zot delivery fail data: ' . print_r($result,true), LOGGER_DATA);
|
||||
self::update($outq['outq_hash'],10);
|
||||
self::update($outq['outq_hash'], 10);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
|
||||
class Share {
|
||||
|
||||
private $item = null;
|
||||
|
||||
|
||||
public function __construct($post_id) {
|
||||
|
||||
|
||||
if(! $post_id)
|
||||
return;
|
||||
|
||||
|
||||
if(! (local_channel() || remote_channel()))
|
||||
return;
|
||||
|
||||
|
||||
$r = q("SELECT * from item left join xchan on author_xchan = xchan_hash WHERE id = %d LIMIT 1",
|
||||
intval($post_id)
|
||||
);
|
||||
@@ -24,26 +23,26 @@ class Share {
|
||||
|
||||
if(($r[0]['item_private']) && ($r[0]['xchan_network'] !== 'rss'))
|
||||
return;
|
||||
|
||||
|
||||
$sql_extra = item_permissions_sql($r[0]['uid']);
|
||||
|
||||
|
||||
$r = q("select * from item where id = %d $sql_extra",
|
||||
intval($post_id)
|
||||
);
|
||||
if(! $r)
|
||||
return;
|
||||
|
||||
|
||||
if($r[0]['mimetype'] !== 'text/bbcode')
|
||||
return;
|
||||
|
||||
|
||||
/** @FIXME eventually we want to post remotely via rpost on your home site */
|
||||
// When that works remove this next bit:
|
||||
|
||||
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
xchan_query($r);
|
||||
|
||||
|
||||
$this->item = $r[0];
|
||||
return;
|
||||
}
|
||||
@@ -54,7 +53,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'];
|
||||
@@ -67,14 +66,14 @@ class Share {
|
||||
'address' => $this->item['author']['xchan_addr'],
|
||||
'network' => $this->item['author']['xchan_network'],
|
||||
'link' => [
|
||||
[
|
||||
'rel' => 'alternate',
|
||||
'type' => 'text/html',
|
||||
[
|
||||
'rel' => 'alternate',
|
||||
'type' => 'text/html',
|
||||
'href' => $this->item['author']['xchan_url']
|
||||
],
|
||||
[
|
||||
'rel' => 'photo',
|
||||
'type' => $this->item['author']['xchan_photo_mimetype'],
|
||||
'rel' => 'photo',
|
||||
'type' => $this->item['author']['xchan_photo_mimetype'],
|
||||
'href' => $this->item['author']['xchan_photo_m']
|
||||
]
|
||||
]
|
||||
@@ -85,14 +84,14 @@ class Share {
|
||||
'address' => $this->item['owner']['xchan_addr'],
|
||||
'network' => $this->item['owner']['xchan_network'],
|
||||
'link' => [
|
||||
[
|
||||
'rel' => 'alternate',
|
||||
'type' => 'text/html',
|
||||
[
|
||||
'rel' => 'alternate',
|
||||
'type' => 'text/html',
|
||||
'href' => $this->item['owner']['xchan_url']
|
||||
],
|
||||
[
|
||||
'rel' => 'photo',
|
||||
'type' => $this->item['owner']['xchan_photo_mimetype'],
|
||||
'rel' => 'photo',
|
||||
'type' => $this->item['owner']['xchan_photo_mimetype'],
|
||||
'href' => $this->item['owner']['xchan_photo_m']
|
||||
]
|
||||
]
|
||||
@@ -118,7 +117,7 @@ class Share {
|
||||
$object = json_decode($this->item['obj'],true);
|
||||
$photo_bb = $object['body'];
|
||||
}
|
||||
|
||||
|
||||
if (strpos($this->item['body'], "[/share]") !== false) {
|
||||
$pos = strpos($this->item['body'], "[share");
|
||||
$bb = substr($this->item['body'], $pos);
|
||||
@@ -127,12 +126,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='" . (($this->item['author']['xchan_network'] === 'zot6') ? '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() {
|
||||
|
||||
@@ -35,7 +35,7 @@ class ThreadItem {
|
||||
|
||||
|
||||
public function __construct($data) {
|
||||
|
||||
|
||||
$this->data = $data;
|
||||
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
|
||||
$this->threaded = get_config('system','thread_allow');
|
||||
@@ -43,7 +43,7 @@ class ThreadItem {
|
||||
$observer = \App::get_observer();
|
||||
|
||||
// Prepare the children
|
||||
if($data['children']) {
|
||||
if(isset($data['children'])) {
|
||||
foreach($data['children'] as $item) {
|
||||
|
||||
/*
|
||||
@@ -78,7 +78,7 @@ class ThreadItem {
|
||||
*/
|
||||
|
||||
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
|
||||
|
||||
|
||||
$result = array();
|
||||
|
||||
$item = $this->get_data();
|
||||
@@ -95,13 +95,14 @@ 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);
|
||||
$locktype = $item['item_private'];
|
||||
|
||||
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false);
|
||||
|
||||
@@ -110,10 +111,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;
|
||||
}
|
||||
|
||||
@@ -150,9 +151,11 @@ class ThreadItem {
|
||||
$edpost = false;
|
||||
|
||||
|
||||
if($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())
|
||||
if($observer && $observer['xchan_hash']
|
||||
&& ($observer['xchan_hash'] == $this->get_data_value('author_xchan')
|
||||
|| $observer['xchan_hash'] == $this->get_data_value('owner_xchan')
|
||||
|| $observer['xchan_hash'] == $this->get_data_value('source_xchan')
|
||||
|| $this->get_data_value('uid') == local_channel()))
|
||||
$dropping = true;
|
||||
|
||||
|
||||
@@ -167,15 +170,15 @@ class ThreadItem {
|
||||
'dropping' => $dropping,
|
||||
'delete' => t('Delete'),
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif(is_site_admin()) {
|
||||
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
|
||||
}
|
||||
|
||||
// FIXME
|
||||
if($observer_is_pageowner) {
|
||||
if($observer_is_pageowner) {
|
||||
$multidrop = array(
|
||||
'select' => t('Select'),
|
||||
'select' => t('Select'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -204,6 +207,10 @@ class ThreadItem {
|
||||
}
|
||||
}
|
||||
|
||||
if($item['obj_type'] === 'Question') {
|
||||
$response_verbs[] = 'answer';
|
||||
}
|
||||
|
||||
$consensus = (intval($item['item_consensus']) ? true : false);
|
||||
if($consensus) {
|
||||
$response_verbs[] = 'agree';
|
||||
@@ -217,7 +224,7 @@ class ThreadItem {
|
||||
|
||||
if(! feature_enabled($conv->get_profile_owner(),'dislike'))
|
||||
unset($conv_responses['dislike']);
|
||||
|
||||
|
||||
$responses = get_responses($conv_responses,$response_verbs,$this,$item);
|
||||
|
||||
$my_responses = [];
|
||||
@@ -248,7 +255,7 @@ class ThreadItem {
|
||||
}
|
||||
|
||||
$showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : '');
|
||||
$showdislike = ((x($conv_responses['dislike'],$item['mid']) && feature_enabled($conv->get_profile_owner(),'dislike'))
|
||||
$showdislike = ((x($conv_responses['dislike'],$item['mid']) && feature_enabled($conv->get_profile_owner(),'dislike'))
|
||||
? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : '');
|
||||
|
||||
/*
|
||||
@@ -258,7 +265,7 @@ class ThreadItem {
|
||||
*/
|
||||
|
||||
$this->check_wall_to_wall();
|
||||
|
||||
|
||||
if($this->is_toplevel()) {
|
||||
// FIXME check this permission
|
||||
if(($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) {
|
||||
@@ -269,7 +276,7 @@ class ThreadItem {
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$is_comment = true;
|
||||
}
|
||||
@@ -281,14 +288,18 @@ 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');
|
||||
$settings = t('Conversation Features');
|
||||
}
|
||||
|
||||
$has_bookmarks = false;
|
||||
@@ -339,15 +350,15 @@ class ThreadItem {
|
||||
|
||||
// $viewthread (below) is only valid in list mode. If this is a channel page, build the thread viewing link
|
||||
// since we can't depend on llink or plink pointing to the right local location.
|
||||
|
||||
|
||||
$owner_address = substr($item['owner']['xchan_addr'],0,strpos($item['owner']['xchan_addr'],'@'));
|
||||
$viewthread = $item['llink'];
|
||||
if($conv->get_mode() === 'channel')
|
||||
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
|
||||
|
||||
$comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children );
|
||||
$list_unseen_txt = (($unseen_comments) ? sprintf('%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);
|
||||
@@ -356,11 +367,28 @@ class ThreadItem {
|
||||
call_hooks('dropdown_extras',$dropdown_extras_arr);
|
||||
$dropdown_extras = $dropdown_extras_arr['dropdown_extras'];
|
||||
|
||||
$midb64 = gen_link_id($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)),
|
||||
'item_type' => intval($item['item_type']),
|
||||
//'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
|
||||
'body' => $body['html'],
|
||||
'tags' => $body['tags'],
|
||||
'categories' => $body['categories'],
|
||||
@@ -369,7 +397,8 @@ 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,
|
||||
@@ -377,8 +406,8 @@ class ThreadItem {
|
||||
'consensus' => $consensus,
|
||||
'conlabels' => $conlabels,
|
||||
'canvote' => $canvote,
|
||||
'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url'])),
|
||||
'olinktitle' => sprintf( t('View %s\'s profile - %s'), $this->get_owner_name(), (($item['owner']['xchan_addr']) ? $item['owner']['xchan_addr'] : $item['owner']['xchan_url'])),
|
||||
'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'),
|
||||
@@ -396,7 +425,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'),
|
||||
@@ -404,6 +433,8 @@ 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,
|
||||
'locktype' => $locktype,
|
||||
'delayed' => $item['item_delayed'],
|
||||
'privacy_warning' => $privacy_warning,
|
||||
'verified' => $verified,
|
||||
'unverified' => $unverified,
|
||||
@@ -437,6 +468,9 @@ 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,
|
||||
@@ -463,14 +497,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,
|
||||
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? $item['thr_parent'] : '')
|
||||
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? 'b64.' . base64url_encode($item['thr_parent']) : '')
|
||||
);
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
@@ -487,8 +520,8 @@ class ThreadItem {
|
||||
|
||||
// needed for scroll to comment from notification but needs more work
|
||||
// as we do not want to open all comments unless there is actually an #item_xx anchor
|
||||
// and the url fragment is not sent to the server.
|
||||
// if(in_array(\App::$module,['display','update_display']))
|
||||
// and the url fragment is not sent to the server.
|
||||
// if(in_array(\App::$module,['display','update_display']))
|
||||
// $visible_comments = 99999;
|
||||
|
||||
if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
|
||||
@@ -508,7 +541,7 @@ class ThreadItem {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$result['private'] = $item['item_private'];
|
||||
$result['toplevel'] = ($this->is_toplevel() ? 'toplevel_item' : '');
|
||||
|
||||
@@ -523,7 +556,7 @@ class ThreadItem {
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function get_id() {
|
||||
return $this->get_data_value('id');
|
||||
}
|
||||
@@ -578,7 +611,7 @@ class ThreadItem {
|
||||
if(activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$item->set_parent($this);
|
||||
$this->children[] = $item;
|
||||
return end($this->children);
|
||||
@@ -652,7 +685,7 @@ class ThreadItem {
|
||||
*/
|
||||
public function set_conversation($conv) {
|
||||
$previous_mode = ($this->conversation ? $this->conversation->get_mode() : '');
|
||||
|
||||
|
||||
$this->conversation = $conv;
|
||||
|
||||
// Set it on our children too
|
||||
@@ -761,7 +794,7 @@ class ThreadItem {
|
||||
if(!$this->is_toplevel() && !get_config('system','thread_allow')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
$comment_box = '';
|
||||
$conv = $this->get_conversation();
|
||||
|
||||
@@ -777,8 +810,6 @@ class ThreadItem {
|
||||
$arr = array('comment_buttons' => '','id' => $this->get_id());
|
||||
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' => '',
|
||||
@@ -814,8 +845,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;
|
||||
@@ -837,7 +867,7 @@ class ThreadItem {
|
||||
|
||||
if($conv->get_mode() === 'channel')
|
||||
return;
|
||||
|
||||
|
||||
if($this->is_toplevel() && ($this->get_data_value('author_xchan') != $this->get_data_value('owner_xchan'))) {
|
||||
$this->owner_url = chanlink_hash($this->data['owner']['xchan_hash']);
|
||||
$this->owner_photo = $this->data['owner']['xchan_photo_m'];
|
||||
@@ -866,7 +896,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
|
||||
@@ -77,7 +77,7 @@ class ThreadStream {
|
||||
$this->reload = $_SESSION['return_url'];
|
||||
break;
|
||||
case 'display':
|
||||
// in this mode we set profile_owner after initialisation (from conversation()) and then
|
||||
// in this mode we set profile_owner after initialisation (from conversation()) and then
|
||||
// pull some trickery which allows us to re-invoke this function afterward
|
||||
// it's an ugly hack so @FIXME
|
||||
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
|
||||
@@ -170,14 +170,14 @@ class ThreadStream {
|
||||
* Only add things that will be displayed
|
||||
*/
|
||||
|
||||
|
||||
|
||||
if(($item->get_data_value('id') != $item->get_data_value('parent')) && (activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$item->set_commentable(false);
|
||||
$ob_hash = (($this->observer) ? $this->observer['xchan_hash'] : '');
|
||||
|
||||
|
||||
if(! comments_are_now_closed($item->get_data())) {
|
||||
if(($item->get_data_value('author_xchan') === $ob_hash) || ($item->get_data_value('owner_xchan') === $ob_hash))
|
||||
$item->set_commentable(true);
|
||||
@@ -194,7 +194,7 @@ class ThreadStream {
|
||||
}
|
||||
if($this->mode === 'pubstream' && (! local_channel())) {
|
||||
$item->set_commentable(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$item->set_conversation($this);
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Zotlabs\Lib;
|
||||
|
||||
class Verify {
|
||||
|
||||
function create($type,$channel_id,$token,$meta) {
|
||||
public static function create($type,$channel_id,$token,$meta) {
|
||||
return q("insert into verify ( vtype, channel, token, meta, created ) values ( '%s', %d, '%s', '%s', '%s' )",
|
||||
dbesc($type),
|
||||
intval($channel_id),
|
||||
@@ -15,7 +15,7 @@ class Verify {
|
||||
);
|
||||
}
|
||||
|
||||
function match($type,$channel_id,$token,$meta) {
|
||||
public static function match($type,$channel_id,$token,$meta) {
|
||||
$r = q("select id from verify where vtype = '%s' and channel = %d and token = '%s' and meta = '%s' limit 1",
|
||||
dbesc($type),
|
||||
intval($channel_id),
|
||||
@@ -31,7 +31,7 @@ class Verify {
|
||||
return false;
|
||||
}
|
||||
|
||||
function get_meta($type,$channel_id,$token) {
|
||||
public static function get_meta($type,$channel_id,$token) {
|
||||
$r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1",
|
||||
dbesc($type),
|
||||
intval($channel_id),
|
||||
@@ -52,7 +52,7 @@ class Verify {
|
||||
* @param string $type Verify type
|
||||
* @param string $interval SQL compatible time interval
|
||||
*/
|
||||
function purge($type, $interval) {
|
||||
public static function purge($type, $interval) {
|
||||
q("delete from verify where vtype = '%s' and created < %s - INTERVAL %s",
|
||||
dbesc($type),
|
||||
db_utcnow(),
|
||||
|
||||
@@ -106,4 +106,4 @@ class Webfinger {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
|
||||
class ZotURL {
|
||||
@@ -21,9 +21,8 @@ class ZotURL {
|
||||
}
|
||||
|
||||
$portable_url = substr($url,6);
|
||||
$u = explode('/',$portable_url);
|
||||
$u = explode('/',$portable_url);
|
||||
$portable_id = $u[0];
|
||||
|
||||
$hosts = self::lookup($portable_id);
|
||||
|
||||
if(! $hosts) {
|
||||
@@ -39,8 +38,8 @@ class ZotURL {
|
||||
|
||||
if($channel && $m) {
|
||||
|
||||
$headers = [
|
||||
'Accept' => 'application/x-zot+json',
|
||||
$headers = [
|
||||
'Accept' => 'application/x-zot+json',
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'X-Zot-Token' => random_string(),
|
||||
'Digest' => HTTPSig::generate_digest_header($data),
|
||||
@@ -50,9 +49,9 @@ class ZotURL {
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
|
||||
}
|
||||
else {
|
||||
$h = [ 'Accept: application/x-zot+json' ];
|
||||
$h = [ 'Accept: application/x-zot+json' ];
|
||||
}
|
||||
|
||||
|
||||
$result = [];
|
||||
|
||||
$redirects = 0;
|
||||
|
||||
@@ -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;
|
||||
@@ -18,8 +18,8 @@ class Zotfinger {
|
||||
|
||||
if($channel && $m) {
|
||||
|
||||
$headers = [
|
||||
'Accept' => 'application/x-zot+json',
|
||||
$headers = [
|
||||
'Accept' => 'application/x-zot+json',
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'X-Zot-Token' => random_string(),
|
||||
'Digest' => HTTPSig::generate_digest_header($data),
|
||||
@@ -29,11 +29,10 @@ class Zotfinger {
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
|
||||
}
|
||||
else {
|
||||
$h = [ 'Accept: application/x-zot+json' ];
|
||||
$h = [ 'Accept: application/x-zot+json' ];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$result = [];
|
||||
|
||||
$redirects = 0;
|
||||
$x = z_post_url($resource,$data,$redirects, [ 'headers' => $h ] );
|
||||
@@ -41,13 +40,14 @@ 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);
|
||||
|
||||
if($result['data'] && is_array($result['data']) && array_key_exists('encrypted',$result['data']) && $result['data']['encrypted']) {
|
||||
$result['data'] = json_decode(crypto_unencapsulate($result['data'],get_config('system','prvkey')),true);
|
||||
$result['data'] = json_decode(Crypto::unencapsulate($result['data'],get_config('system','prvkey')),true);
|
||||
}
|
||||
|
||||
logger('decrypted: ' . print_r($result,true));
|
||||
@@ -60,4 +60,4 @@ class Zotfinger {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
|
||||
require_once 'include/acl_selectors.php';
|
||||
require_once 'include/group.php';
|
||||
|
||||
@@ -42,24 +44,24 @@ 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.
|
||||
|
||||
// List of channels whose connections to also suggest,
|
||||
|
||||
// List of channels whose connections to also suggest,
|
||||
// e.g. currently viewed channel or channels mentioned in a post
|
||||
|
||||
$extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array());
|
||||
|
||||
|
||||
// The different autocomplete libraries use different names for the search text
|
||||
// parameter. Internally we'll use $search to represent the search text no matter
|
||||
// what request variable it was attached to.
|
||||
|
||||
// what request variable it was attached to.
|
||||
|
||||
if(array_key_exists('query',$_REQUEST)) {
|
||||
$search = $_REQUEST['query'];
|
||||
}
|
||||
|
||||
|
||||
if( (! local_channel()) && (! in_array($type, [ 'x', 'c', 'f' ])))
|
||||
killme();
|
||||
|
||||
@@ -68,7 +70,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
if(in_array($type, [ 'm', 'a', 'c', 'f' ])) {
|
||||
|
||||
// These queries require permission checking. We'll create a simple array of xchan_hash for those with
|
||||
// the requisite permissions which we can check against.
|
||||
// the requisite permissions which we can check against.
|
||||
|
||||
$x = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = '%s' and v = '1'",
|
||||
intval(local_channel()),
|
||||
@@ -85,34 +87,34 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
$sql_extra2 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") ";
|
||||
$sql_extra2_xchan = "AND ( xchan_name LIKE " . protect_sprintf( "'" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") ";
|
||||
|
||||
// This horrible mess is needed because position also returns 0 if nothing is found.
|
||||
// This horrible mess is needed because position also returns 0 if nothing is found.
|
||||
// Would be MUCH easier if it instead returned a very large value
|
||||
// Otherwise we could just
|
||||
// Otherwise we could just
|
||||
// order by LEAST(POSITION($search IN xchan_name),POSITION($search IN xchan_addr)).
|
||||
|
||||
$order_extra2 = "CASE WHEN xchan_name LIKE "
|
||||
. protect_sprintf( "'%" . dbesc($search) . "%'" )
|
||||
. " then POSITION('" . protect_sprintf(dbesc($search))
|
||||
$order_extra2 = "CASE WHEN xchan_name LIKE "
|
||||
. protect_sprintf( "'%" . dbesc($search) . "%'" )
|
||||
. " then POSITION('" . protect_sprintf(dbesc($search))
|
||||
. "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, ";
|
||||
|
||||
$sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) ";
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
$sql_extra = $sql_extra2 = $sql_extra3 = "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
$groups = array();
|
||||
$contacts = array();
|
||||
|
||||
|
||||
if($type == '' || $type == 'g') {
|
||||
|
||||
// virtual groups based on private profile viewing ability
|
||||
|
||||
$r = q("select id, profile_guid, profile_name from profile where is_default = 0 and uid = %d",
|
||||
intval(local_channel())
|
||||
);
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rv) {
|
||||
$groups[] = array(
|
||||
@@ -130,19 +132,19 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
// Normal privacy groups
|
||||
|
||||
$r = q("SELECT pgrp.id, pgrp.hash, pgrp.gname
|
||||
FROM pgrp, pgrp_member
|
||||
WHERE pgrp.deleted = 0 AND pgrp.uid = %d
|
||||
FROM pgrp, pgrp_member
|
||||
WHERE pgrp.deleted = 0 AND pgrp.uid = %d
|
||||
AND pgrp_member.gid = pgrp.id
|
||||
$sql_extra
|
||||
GROUP BY pgrp.id
|
||||
ORDER BY pgrp.gname
|
||||
ORDER BY pgrp.gname
|
||||
LIMIT %d OFFSET %d",
|
||||
intval(local_channel()),
|
||||
intval($count),
|
||||
intval($start)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
if($r) {
|
||||
foreach($r as $g){
|
||||
// logger('acl: group: ' . $g['gname'] . ' members: ' . group_get_members_xchan($g['id']));
|
||||
$groups[] = array(
|
||||
@@ -157,10 +159,10 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($type == '' || $type == 'c' || $type === 'f') {
|
||||
|
||||
$extra_channels_sql = '';
|
||||
$extra_channels_sql = '';
|
||||
|
||||
// Only include channels who allow the observer to view their connections
|
||||
if($extra_channels) {
|
||||
@@ -172,7 +174,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Getting info from the abook is better for local users because it contains info about permissions
|
||||
if(local_channel()) {
|
||||
if($extra_channels_sql != '')
|
||||
@@ -199,7 +201,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
$r2 = array();
|
||||
foreach($r1 as $rr) {
|
||||
$x = atoken_xchan($rr);
|
||||
$r2[] = [
|
||||
$r2[] = [
|
||||
'id' => 'a' . $rr['atoken_id'] ,
|
||||
'hash' => $x['xchan_hash'],
|
||||
'name' => $x['xchan_name'],
|
||||
@@ -211,42 +213,43 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
'abook_self' => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add connections
|
||||
|
||||
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, xchan_pubforum, abook_flags, abook_self
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
|
||||
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, xchan_pubforum, abook_flags, abook_self
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if($r2)
|
||||
$r = array_merge($r2,$r);
|
||||
|
||||
}
|
||||
else { // Visitors
|
||||
$r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
|
||||
$r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
|
||||
FROM xchan left join xlink on xlink_link = xchan_hash
|
||||
WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2_xchan order by $order_extra2 xchan_name asc" ,
|
||||
dbesc(get_observer_hash())
|
||||
);
|
||||
|
||||
|
||||
// Find contacts of extra channels
|
||||
// This is probably more complicated than it needs to be
|
||||
if($extra_channels_sql) {
|
||||
// Build a list of hashes that we got previously so we don't get them again
|
||||
$known_hashes = array("'".get_observer_hash()."'");
|
||||
if($r)
|
||||
foreach($r as $rr)
|
||||
foreach($r as $rr)
|
||||
$known_hashes[] = "'".$rr['hash']."'";
|
||||
$known_hashes_sql = 'AND xchan_hash not in ('.join(',',$known_hashes).')';
|
||||
|
||||
$r2 = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags, abook_self
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
|
||||
$r2 = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags, abook_self
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel IN ($extra_channels_sql) $known_hashes_sql AND abook_blocked = 0 and abook_pending = 0 and abook_hidden = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc");
|
||||
if($r2)
|
||||
$r = array_merge($r,$r2);
|
||||
|
||||
|
||||
// Sort accoring to match position, then alphabetically. This could be avoided if the above two SQL queries could be combined into one, and the sorting could be done on the SQl server (like in the case of a local user)
|
||||
$matchpos = function($x) use($search) {
|
||||
$namepos = strpos($x['name'],$search);
|
||||
@@ -269,23 +272,23 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
if((count($r) < 100) && $type == 'c') {
|
||||
$r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
|
||||
FROM xchan
|
||||
$r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
|
||||
FROM xchan
|
||||
WHERE xchan_deleted = 0 and not xchan_network in ('rss','anon','unknown') $sql_extra2_xchan order by $order_extra2 xchan_name asc"
|
||||
);
|
||||
if($r2) {
|
||||
$r = array_merge($r,$r2);
|
||||
$r = unique_multidim_array($r,'hash');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($type == 'm') {
|
||||
|
||||
$r = array();
|
||||
$z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url
|
||||
$z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d
|
||||
WHERE abook_channel = %d
|
||||
and xchan_deleted = 0
|
||||
and not xchan_network IN ('rss', 'anon', 'unknown')
|
||||
$sql_extra3
|
||||
ORDER BY xchan_name ASC ",
|
||||
intval(local_channel())
|
||||
@@ -297,18 +300,18 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
elseif($type == 'a') {
|
||||
|
||||
$r = q("SELECT abook_id as id, xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag , abook_their_perms FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
|
||||
$r = q("SELECT abook_id as id, xchan_name as name, xchan_network as net, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url, xchan_addr as attag , abook_their_perms FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d
|
||||
and xchan_deleted = 0
|
||||
$sql_extra3
|
||||
ORDER BY xchan_name ASC ",
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
elseif($type == 'x') {
|
||||
$r = $this->navbar_complete($a);
|
||||
@@ -322,7 +325,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$o = array(
|
||||
'start' => $start,
|
||||
'count' => $count,
|
||||
@@ -333,27 +336,34 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
else
|
||||
$r = array();
|
||||
|
||||
|
||||
if($r) {
|
||||
$i = count($contacts);
|
||||
$x = [];
|
||||
foreach($r as $g) {
|
||||
|
||||
if(in_array($g['network'],['rss','anon','unknown']) && ($type != 'a'))
|
||||
|
||||
if(in_array($g['net'],['rss','anon','unknown']) && ($type != 'a'))
|
||||
continue;
|
||||
|
||||
$g['hash'] = urlencode($g['hash']);
|
||||
|
||||
|
||||
if(! $g['nick']) {
|
||||
$g['nick'] = $g['url'];
|
||||
}
|
||||
|
||||
$clink = ($g['nick']) ? $g['nick'] : $g['url'];
|
||||
$lkey = md5($clink);
|
||||
if (! array_key_exists($lkey, $x))
|
||||
$x[$lkey] = $i;
|
||||
|
||||
if(in_array($g['hash'],$permitted) && $type === 'f' && (! $noforums)) {
|
||||
$contacts[] = array(
|
||||
$contacts[$i] = array(
|
||||
"type" => "c",
|
||||
"photo" => "images/twopeople.png",
|
||||
"name" => $g['name'],
|
||||
"id" => urlencode($g['id']),
|
||||
"xid" => $g['hash'],
|
||||
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
|
||||
"link" => $clink,
|
||||
"nick" => substr($g['nick'],0,strpos($g['nick'],'@')),
|
||||
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
|
||||
"taggable" => 'taggable',
|
||||
@@ -361,24 +371,28 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
}
|
||||
if($type !== 'f') {
|
||||
$contacts[] = array(
|
||||
"type" => "c",
|
||||
"photo" => $g['micro'],
|
||||
"name" => $g['name'],
|
||||
"id" => urlencode($g['id']),
|
||||
"xid" => $g['hash'],
|
||||
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
|
||||
"nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
|
||||
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
|
||||
"taggable" => '',
|
||||
"label" => '',
|
||||
);
|
||||
if (! array_key_exists($x[$lkey], $contacts) || ($contacts[$x[$lkey]]['net'] !== 'zot6' && $g['net'] == 'zot6')) {
|
||||
$contacts[$x[$lkey]] = array(
|
||||
"type" => "c",
|
||||
"photo" => $g['micro'],
|
||||
"name" => $g['name'],
|
||||
"id" => urlencode($g['id']),
|
||||
"xid" => $g['hash'],
|
||||
"link" => $clink,
|
||||
"nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
|
||||
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
|
||||
"taggable" => '',
|
||||
"label" => '',
|
||||
"net" => $g['net']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$items = array_merge($groups, $contacts);
|
||||
|
||||
|
||||
$o = array(
|
||||
'start' => $start,
|
||||
'count' => $count,
|
||||
@@ -392,50 +406,49 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
function navbar_complete(&$a) {
|
||||
|
||||
|
||||
// logger('navbar_complete');
|
||||
|
||||
|
||||
if(observer_prohibited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$dirmode = intval(get_config('system','directory_mode'));
|
||||
$search = ((x($_REQUEST,'search')) ? htmlentities($_REQUEST['search'],ENT_COMPAT,'UTF-8',false) : '');
|
||||
if(! $search || mb_strlen($search) < 2)
|
||||
return array();
|
||||
|
||||
|
||||
$star = false;
|
||||
$address = false;
|
||||
|
||||
|
||||
if(substr($search,0,1) === '@')
|
||||
$search = substr($search,1);
|
||||
|
||||
|
||||
if(substr($search,0,1) === '*') {
|
||||
$star = true;
|
||||
$search = substr($search,1);
|
||||
}
|
||||
|
||||
|
||||
if(strpos($search,'@') !== false) {
|
||||
$address = true;
|
||||
}
|
||||
|
||||
|
||||
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
|
||||
$url = z_root() . '/dirsearch';
|
||||
}
|
||||
|
||||
|
||||
if(! $url) {
|
||||
require_once("include/dir_fns.php");
|
||||
$directory = find_upstream_directory($dirmode);
|
||||
$directory = Libzotdir::find_upstream_directory($dirmode);
|
||||
$url = $directory['url'] . '/dirsearch';
|
||||
}
|
||||
|
||||
$token = get_config('system','realm_token');
|
||||
|
||||
|
||||
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
|
||||
if($url) {
|
||||
$query = $url . '?f=' . (($token) ? '&t=' . urlencode($token) : '');
|
||||
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
|
||||
|
||||
|
||||
$x = z_fetch_url($query);
|
||||
if($x['success']) {
|
||||
$t = 0;
|
||||
|
||||
288
Zotlabs/Module/Activity.php
Normal file
288
Zotlabs/Module/Activity.php
Normal file
@@ -0,0 +1,288 @@
|
||||
<?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_extra = sprintf(" and not verb in ('%s', '%s') ",
|
||||
dbesc(ACTIVITY_FOLLOW),
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
|
||||
$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 && (! intval($items[0]['item_private']))) {
|
||||
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_extra = sprintf(" and not verb in ('%s', '%s') ",
|
||||
dbesc(ACTIVITY_FOLLOW),
|
||||
dbesc(ACTIVITY_UNFOLLOW)
|
||||
);
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
|
||||
|
||||
$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);
|
||||
|
||||
if ($portable_id && (! intval($items[0]['item_private']))) {
|
||||
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
|
||||
intval($items[0]['uid']),
|
||||
dbesc($portable_id)
|
||||
);
|
||||
if (! $c) {
|
||||
ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id);
|
||||
}
|
||||
}
|
||||
|
||||
$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));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/queue_fn.php');
|
||||
require_once('include/account.php');
|
||||
|
||||
/**
|
||||
@@ -101,11 +100,14 @@ class Admin extends \Zotlabs\Web\Controller {
|
||||
|
||||
// pending registrations
|
||||
|
||||
$pdg = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) > 0 ",
|
||||
intval(ACCOUNT_PENDING)
|
||||
// $pdg = q("SELECT account.*, register.reg_hash from account left join register on account_id = register.reg_uid // where (account_flags & %d ) > 0 ",
|
||||
// intval(ACCOUNT_PENDING)
|
||||
// );
|
||||
$pdg = q("SELECT COUNT(*) AS pdg FROM register WHERE reg_vital = 1 AND reg_expires > '%s' ",
|
||||
dbesc(date('Y-m-d H:i:s'))
|
||||
);
|
||||
|
||||
$pending = (($pdg) ? count($pdg) : 0);
|
||||
$pending = ($pdg ? $pdg[0]['pdg'] : 0);
|
||||
|
||||
// available channels, primary and clones
|
||||
$channels = array();
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Zotlabs\Module\Admin;
|
||||
|
||||
|
||||
class Accounts {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle POST actions on accounts admin page.
|
||||
*
|
||||
@@ -15,14 +15,105 @@ class Accounts {
|
||||
*
|
||||
*/
|
||||
|
||||
const MYP = 'ZAR'; // ZAR2x
|
||||
const VERSION = '2.0.0';
|
||||
|
||||
function post() {
|
||||
|
||||
$pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
|
||||
$users = ( x($_POST, 'user') ? $_POST['user'] : array() );
|
||||
$blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : array() );
|
||||
|
||||
|
||||
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
|
||||
|
||||
|
||||
$isajax = is_ajax();
|
||||
$rc = 0;
|
||||
|
||||
If (!is_site_admin()) {
|
||||
if ($isajax) {
|
||||
killme();
|
||||
exit;
|
||||
}
|
||||
goaway(z_root() . '/');
|
||||
}
|
||||
|
||||
if ($isajax) {
|
||||
//$debug = print_r($_SESSION[self::MYP],true);
|
||||
$zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
|
||||
? $_POST['zardo'] : '';
|
||||
// zarat arrives with leading underscore _n
|
||||
$zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
|
||||
? substr($_POST['zarat'],1) : '';
|
||||
$zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
|
||||
? hex2bin($_POST['zarse']) : '';
|
||||
|
||||
if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
|
||||
|
||||
//
|
||||
if ($zarop == 'd') {
|
||||
$rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat]),
|
||||
dbesc($_SESSION[self::MYP]['h'][$zarat])
|
||||
);
|
||||
$rc = '×';
|
||||
}
|
||||
elseif ($zarop == 'a') {
|
||||
// approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
|
||||
$rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
|
||||
. " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
|
||||
. " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat]),
|
||||
dbesc($_SESSION[self::MYP]['h'][$zarat])
|
||||
);
|
||||
$rc = 0;
|
||||
$rs = q("SELECT * from register WHERE reg_id = %d ",
|
||||
intval($_SESSION[self::MYP]['i'][$zarat])
|
||||
);
|
||||
if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
|
||||
// create account
|
||||
$rc = 'ok'.$rs[0]['reg_id'];
|
||||
$ac = create_account_from_register($rs[0]);
|
||||
if ( $ac['success'] ) {
|
||||
$rc .= '✔';
|
||||
|
||||
$auto_create = get_config('system','auto_channel_create',1);
|
||||
|
||||
if($auto_create) {
|
||||
$reonar = json_decode($rs[0]['reg_stuff'], true);
|
||||
// prepare channel creation
|
||||
if($reonar['chan.name'])
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
|
||||
|
||||
if($reonar['chan.did1'])
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
|
||||
|
||||
$permissions_role = get_config('system','default_permissions_role');
|
||||
if($permissions_role)
|
||||
set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
|
||||
|
||||
// create channel
|
||||
$new_channel = auto_channel_create($ac['account']['account_id']);
|
||||
|
||||
if($new_channel['success']) {
|
||||
$rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
|
||||
}
|
||||
else {
|
||||
$rc .= ' c ×';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
$rc='oh ×';
|
||||
}
|
||||
}
|
||||
echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
|
||||
}
|
||||
killme();
|
||||
exit;
|
||||
}
|
||||
|
||||
// change to switch structure?
|
||||
// account block/unblock button was submitted
|
||||
if (x($_POST, 'page_accounts_block')) {
|
||||
@@ -55,7 +146,7 @@ class Accounts {
|
||||
account_deny($hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
goaway(z_root() . '/admin/accounts' );
|
||||
}
|
||||
|
||||
@@ -75,19 +166,21 @@ class Accounts {
|
||||
$account = q("SELECT * FROM account WHERE account_id = %d",
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
|
||||
if (! $account) {
|
||||
notice( t('Account not found') . EOL);
|
||||
goaway(z_root() . '/admin/accounts' );
|
||||
}
|
||||
|
||||
|
||||
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't');
|
||||
|
||||
|
||||
$debug = '';
|
||||
|
||||
switch (argv(2)){
|
||||
case 'delete':
|
||||
// delete user
|
||||
account_remove($uid,true,false);
|
||||
|
||||
|
||||
notice( sprintf(t("Account '%s' deleted"), $account[0]['account_email']) . EOL);
|
||||
break;
|
||||
case 'block':
|
||||
@@ -95,7 +188,7 @@ class Accounts {
|
||||
intval(ACCOUNT_BLOCKED),
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
|
||||
notice( sprintf( t("Account '%s' blocked") , $account[0]['account_email']) . EOL);
|
||||
break;
|
||||
case 'unblock':
|
||||
@@ -103,27 +196,74 @@ class Accounts {
|
||||
intval(ACCOUNT_BLOCKED),
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
|
||||
notice( sprintf( t("Account '%s' unblocked"), $account[0]['account_email']) . EOL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
goaway(z_root() . '/admin/accounts' );
|
||||
}
|
||||
|
||||
/* get pending */
|
||||
$pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d )>0 ",
|
||||
intval(ACCOUNT_PENDING)
|
||||
);
|
||||
|
||||
|
||||
$tao = 'tao.zar.zarax = ' . "'" . '<img src="' . z_root() . '/images/zapax16.gif">' . "';\n";
|
||||
|
||||
|
||||
// by default we will only return verified results. if reg_all is set we will return everything''
|
||||
$get_all = isset($_REQUEST['get_all']);
|
||||
$pending = get_pending_accounts($get_all);
|
||||
|
||||
unset($_SESSION[self::MYP]);
|
||||
|
||||
if ($pending) {
|
||||
// collect and group all ip
|
||||
$atips = dbq("SELECT reg_atip AS atip, COUNT(reg_atip) AS atips FROM register
|
||||
WHERE reg_vital = 1 GROUP BY reg_atip"
|
||||
);
|
||||
|
||||
(($atips) ? $atipn = array_column($atips, 'atips', 'atip') : $atipn = ['' => 0]);
|
||||
|
||||
$tao .= 'tao.zar.zarar = {';
|
||||
foreach ($pending as $n => $v) {
|
||||
|
||||
$stuff = json_decode($v['reg_stuff'], true);
|
||||
|
||||
if(isset($stuff['msg'])) {
|
||||
$pending[$n]['msg'] = $stuff['msg'];
|
||||
}
|
||||
|
||||
if (array_key_exists($v['reg_atip'], $atipn)) {
|
||||
$pending[$n]['reg_atip'] = $v['reg_atip'];
|
||||
$pending[$n]['reg_atip_n'] = $atipn[$v['reg_atip']];
|
||||
}
|
||||
|
||||
$pending[$n]['status'] = '';
|
||||
if($pending[$n]['reg_flags'] & ACCOUNT_UNVERIFIED > 0)
|
||||
$pending[$n]['status'] = [t('Unverified'), 'bg-warning'];
|
||||
|
||||
if($pending[$n]['status'] && $pending[$n]['reg_expires'] < datetime_convert())
|
||||
$pending[$n]['status'] = [t('Expired'), 'bg-danger text-white'];
|
||||
|
||||
// timezone adjust date_time for display
|
||||
$pending[$n]['reg_created'] = datetime_convert('UTC', date_default_timezone_get(), $pending[$n]['reg_created']);
|
||||
$pending[$n]['reg_startup'] = datetime_convert('UTC', date_default_timezone_get(), $pending[$n]['reg_startup']);
|
||||
$pending[$n]['reg_expires'] = datetime_convert('UTC', date_default_timezone_get(), $pending[$n]['reg_expires']);
|
||||
|
||||
// better secure
|
||||
$tao .= $n . ": '" . substr(bin2hex($v['reg_hash']),0,8) . "',";
|
||||
$_SESSION[self::MYP]['h'][] = substr($v['reg_hash'],0,4);
|
||||
$_SESSION[self::MYP]['i'][] = $v['reg_id'];
|
||||
}
|
||||
$tao = rtrim($tao,',') . '};' . "\n";
|
||||
}
|
||||
// <- hilmar]
|
||||
|
||||
/* get accounts */
|
||||
|
||||
|
||||
$total = q("SELECT count(*) as total FROM account");
|
||||
if (count($total)) {
|
||||
\App::set_pager_total($total[0]['total']);
|
||||
\App::set_pager_itemspage(100);
|
||||
}
|
||||
|
||||
|
||||
$serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : '');
|
||||
|
||||
$key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'account_id');
|
||||
@@ -134,8 +274,8 @@ class Accounts {
|
||||
$base = z_root() . '/admin/accounts?f=';
|
||||
$odir = (($dir === 'asc') ? '0' : '1');
|
||||
|
||||
$users = q("SELECT account_id , account_email, account_lastlog, account_created, account_expires, account_service_class, ( account_flags & %d ) > 0 as blocked,
|
||||
(SELECT %s FROM channel as ch WHERE ch.channel_account_id = ac.account_id and ch.channel_removed = 0 ) as channels FROM account as ac
|
||||
$users = q("SELECT account_id , account_email, account_lastlog, account_created, account_expires, account_service_class, ( account_flags & %d ) > 0 as blocked,
|
||||
(SELECT %s FROM channel as ch WHERE ch.channel_account_id = ac.account_id and ch.channel_removed = 0 ) as channels FROM account as ac
|
||||
where true $serviceclass and account_flags != %d order by $key $dir limit %d offset %d ",
|
||||
intval(ACCOUNT_BLOCKED),
|
||||
db_concat('ch.channel_address', ' '),
|
||||
@@ -143,15 +283,15 @@ class Accounts {
|
||||
intval(\App::$pager['itemspage']),
|
||||
intval(\App::$pager['start'])
|
||||
);
|
||||
|
||||
|
||||
// function _setup_users($e){
|
||||
// $accounts = Array(
|
||||
// t('Normal Account'),
|
||||
// t('Normal Account'),
|
||||
// t('Soapbox Account'),
|
||||
// t('Community/Celebrity Account'),
|
||||
// t('Automatic Friend Account')
|
||||
// );
|
||||
|
||||
|
||||
// $e['page_flags'] = $accounts[$e['page-flags']];
|
||||
// $e['register_date'] = relative_date($e['register_date']);
|
||||
// $e['login_date'] = relative_date($e['login_date']);
|
||||
@@ -159,49 +299,57 @@ class Accounts {
|
||||
// return $e;
|
||||
// }
|
||||
// $users = array_map("_setup_users", $users);
|
||||
|
||||
|
||||
$t = get_markup_template('admin_accounts.tpl');
|
||||
$o = replace_macros($t, array(
|
||||
// strings //
|
||||
'$debug' => $debug,
|
||||
'$title' => t('Administration'),
|
||||
'$page' => t('Accounts'),
|
||||
'$submit' => t('Submit'),
|
||||
'$select_all' => t('select all'),
|
||||
'$h_pending' => t('Registrations waiting for confirm'),
|
||||
'$th_pending' => array( t('Request date'), t('Email') ),
|
||||
'$no_pending' => t('No registrations.'),
|
||||
'$get_all' => (($get_all) ? t('Show verified registrations') : t('Show all registrations')),
|
||||
'$get_all_link' => (($get_all) ? z_root() .'/admin/accounts' : z_root() .'/admin/accounts?get_all'),
|
||||
'$sel_tall' => t('Select toggle'),
|
||||
'$sel_deny' => t('Deny selected'),
|
||||
'$sel_aprv' => t('Approve selected'),
|
||||
'$h_pending' => (($get_all) ? t('All registrations') : t('Verified registrations waiting for approval')),
|
||||
'$th_pending' => array(t('Request date'), 'dId2', t('Email'), 'IP', t('Requests')),
|
||||
'$no_pending' => (($get_all) ? t('No registrations available') : t('No verified registrations available')),
|
||||
'$approve' => t('Approve'),
|
||||
'$deny' => t('Deny'),
|
||||
'$delete' => t('Delete'),
|
||||
'$block' => t('Block'),
|
||||
'$unblock' => t('Unblock'),
|
||||
'$verified' => t('Verified'),
|
||||
'$not_verified' => t('Not yet verified'),
|
||||
'$odir' => $odir,
|
||||
'$base' => $base,
|
||||
'$h_users' => t('Accounts'),
|
||||
'$th_users' => array(
|
||||
'$th_users' => array(
|
||||
[ t('ID'), 'account_id' ],
|
||||
[ t('Email'), 'account_email' ],
|
||||
[ t('All Channels'), 'channels' ],
|
||||
[ t('All channels'), 'channels' ],
|
||||
[ t('Register date'), 'account_created' ],
|
||||
[ t('Last login'), 'account_lastlog' ],
|
||||
[ t('Expires'), 'account_expires' ],
|
||||
[ t('Service Class'), 'account_service_class'] ),
|
||||
|
||||
'$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'),
|
||||
'$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'),
|
||||
|
||||
[ t('Service class'), 'account_service_class'] ),
|
||||
|
||||
'$confirm_delete_multi' => p2j(t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?')),
|
||||
'$confirm_delete' => p2j(t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?')),
|
||||
|
||||
'$form_security_token' => get_form_security_token("admin_accounts"),
|
||||
|
||||
|
||||
// values //
|
||||
'$baseurl' => z_root(),
|
||||
|
||||
'$pending' => $pending,
|
||||
'$users' => $users,
|
||||
'$baseurl' => z_root(),
|
||||
'$tao' => $tao,
|
||||
'$pending' => $pending,
|
||||
'$users' => $users,
|
||||
'$msg' => t('Message')
|
||||
));
|
||||
$o .= paginate($a);
|
||||
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -173,4 +173,4 @@ class Channels {
|
||||
return $o;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,35 +2,35 @@
|
||||
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
|
||||
use Zotlabs\Lib\Queue as LibQueue;
|
||||
|
||||
class Queue {
|
||||
|
||||
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
$o = '';
|
||||
|
||||
|
||||
$expert = ((array_key_exists('expert',$_REQUEST)) ? intval($_REQUEST['expert']) : 0);
|
||||
|
||||
|
||||
if($_REQUEST['drophub']) {
|
||||
hubloc_mark_as_down($_REQUEST['drophub']);
|
||||
remove_queue_by_posturl($_REQUEST['drophub']);
|
||||
LibQueue::remove_by_posturl($_REQUEST['drophub']);
|
||||
}
|
||||
|
||||
|
||||
if($_REQUEST['emptyhub']) {
|
||||
remove_queue_by_posturl($_REQUEST['emptyhub']);
|
||||
LibQueue::remove_by_posturl($_REQUEST['emptyhub']);
|
||||
}
|
||||
|
||||
$r = q("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq
|
||||
|
||||
$r = q("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq
|
||||
where outq_delivered = 0 group by outq_posturl order by total desc");
|
||||
|
||||
|
||||
for($x = 0; $x < count($r); $x ++) {
|
||||
$r[$x]['eurl'] = urlencode($r[$x]['outq_posturl']);
|
||||
$r[$x]['connected'] = datetime_convert('UTC',date_default_timezone_get(),$r[$x]['connected'],'Y-m-d');
|
||||
}
|
||||
|
||||
|
||||
$o = replace_macros(get_markup_template('admin_queue.tpl'), array(
|
||||
'$banner' => t('Queue Statistics'),
|
||||
'$numentries' => t('Total Entries'),
|
||||
@@ -43,11 +43,11 @@ class Queue {
|
||||
'$entries' => $r,
|
||||
'$expert' => $expert
|
||||
));
|
||||
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,25 @@ namespace Zotlabs\Module\Admin;
|
||||
|
||||
class Site {
|
||||
|
||||
|
||||
/**
|
||||
* @brief POST handler for Admin Site Page.
|
||||
*
|
||||
*/
|
||||
function post(){
|
||||
// [hilmar->
|
||||
$this->isajax = is_ajax();
|
||||
$this->eol = $this->isajax ? "\n" : EOL;
|
||||
// ]
|
||||
if (!x($_POST, 'page_site')) {
|
||||
return;
|
||||
// [
|
||||
if (!$this->isajax)
|
||||
// ]
|
||||
return;
|
||||
}
|
||||
// [
|
||||
$this->msgbg = '';
|
||||
// <-hilmar]
|
||||
|
||||
check_form_security_token_redirectOnErr('/admin/site', 'admin_site');
|
||||
|
||||
@@ -24,14 +35,17 @@ class Site {
|
||||
$siteinfo = ((x($_POST,'siteinfo')) ? trim($_POST['siteinfo']) : '');
|
||||
$language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : '');
|
||||
$theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : '');
|
||||
// $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : '');
|
||||
// $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : '');
|
||||
// $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : '');
|
||||
// $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : '');
|
||||
$maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0);
|
||||
|
||||
$register_policy = ((x($_POST,'register_policy')) ? intval(trim($_POST['register_policy'])) : 0);
|
||||
$register_wo_email = ((x($_POST,'register_wo_email')) ? intval(trim($_POST['register_wo_email'])) : 0);
|
||||
$minimum_age = ((x($_POST,'minimum_age')) ? intval(trim($_POST['minimum_age'])) : 13);
|
||||
$access_policy = ((x($_POST,'access_policy')) ? intval(trim($_POST['access_policy'])) : 0);
|
||||
$invite_only = ((x($_POST,'invite_only')) ? True : False);
|
||||
$reg_autochannel = ((x($_POST,'auto_channel_create')) ? True : False);
|
||||
$invitation_only = ((x($_POST,'invitation_only')) ? True : False);
|
||||
$invitation_also = ((x($_POST,'invitation_also')) ? True : False);
|
||||
$abandon_days = ((x($_POST,'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0);
|
||||
|
||||
$register_text = ((x($_POST,'register_text')) ? notags(trim($_POST['register_text'])) : '');
|
||||
@@ -62,6 +76,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'])) : '');
|
||||
@@ -72,14 +89,52 @@ class Site {
|
||||
$maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50);
|
||||
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
|
||||
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
|
||||
$register_perday = ((x($_POST,'register_perday')) ? intval(trim($_POST['register_perday'])) : 50);
|
||||
$register_sameip = ((x($_POST,'register_sameip')) ? intval(trim($_POST['register_sameip'])) : 3);
|
||||
|
||||
$regdelayn = ((x($_POST,'zardelayn')) ? intval(trim($_POST['zardelayn'])) : 0);
|
||||
$regdelayu = ((x($_POST,'zardelay')) ? notags(trim($_POST['zardelay'])) : '');
|
||||
$reg_delay = (preg_match('/^[a-z]{1,1}$/', $regdelayu) ? $regdelayn . $regdelayu : '');
|
||||
$regexpiren = ((x($_POST,'zarexpiren')) ? intval(trim($_POST['zarexpiren'])) : 0);
|
||||
$regexpireu = ((x($_POST,'zarexpire')) ? notags(trim($_POST['zarexpire'])) : '');
|
||||
$reg_expire = (preg_match('/^[a-z]{1,1}$/', $regexpireu) ? $regexpiren . $regexpireu : '');
|
||||
|
||||
$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']));
|
||||
|
||||
$permissions_role = escape_tags(trim($_POST['permissions_role']));
|
||||
|
||||
// [hilmar->
|
||||
$this->register_duty = ((x($_POST,'register_duty')) ? notags(trim($_POST['register_duty'])) : '');
|
||||
if (! preg_match('/^[0-9 .,:\-]{0,191}$/', $this->register_duty)) {
|
||||
$this->msgbg .= 'ZAR0131E,' . t('Invalid input') . $this->eol;
|
||||
$this->error++;
|
||||
} else {
|
||||
|
||||
$this->duty();
|
||||
|
||||
if ($this->isajax) {
|
||||
echo json_encode(array('msgbg' => $this->msgbg, 'me' => 'zar'));
|
||||
// that mission is complete
|
||||
killme();
|
||||
exit;
|
||||
|
||||
} else {
|
||||
|
||||
//logger( print_r( $this->msgbg, true) );
|
||||
//logger( print_r( $this->joo, true) );
|
||||
if ($this->error === 0) {
|
||||
set_config('system', 'register_duty', $this->register_duty);
|
||||
set_config('system', 'register_duty_jso', $this->joo);
|
||||
} else {
|
||||
notice('ZAR0130E,'.t('Errors') . ': ' . $this->error) . EOL . $this->msgfg;
|
||||
}
|
||||
}
|
||||
}
|
||||
// <-hilmar]
|
||||
|
||||
set_config('system', 'feed_contacts', $feed_contacts);
|
||||
set_config('system', 'delivery_interval', $delivery_interval);
|
||||
set_config('system', 'delivery_batch_count', $delivery_batch_count);
|
||||
@@ -94,13 +149,16 @@ class Site {
|
||||
set_config('system', 'login_on_homepage', $login_on_homepage);
|
||||
set_config('system', 'enable_context_help', $enable_context_help);
|
||||
set_config('system', 'verify_email', $verify_email);
|
||||
set_config('system', 'max_daily_registrations', $register_perday);
|
||||
set_config('system', 'register_sameip', $register_sameip);
|
||||
set_config('system', 'register_delay', $reg_delay);
|
||||
set_config('system', 'register_expire', $reg_expire);
|
||||
set_config('system', 'default_expire_days', $default_expire_days);
|
||||
set_config('system', 'active_expire_days', $active_expire_days);
|
||||
set_config('system', 'reply_address', $reply_address);
|
||||
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);
|
||||
@@ -125,17 +183,20 @@ class Site {
|
||||
set_config('system','siteinfo',$siteinfo);
|
||||
set_config('system', 'language', $language);
|
||||
set_config('system', 'theme', $theme);
|
||||
// if ( $theme_mobile === '---' ) {
|
||||
// del_config('system', 'mobile_theme');
|
||||
// } else {
|
||||
// set_config('system', 'mobile_theme', $theme_mobile);
|
||||
// }
|
||||
// set_config('system','site_channel', $site_channel);
|
||||
// if ( $theme_mobile === '---' ) {
|
||||
// del_config('system', 'mobile_theme');
|
||||
// } else {
|
||||
// set_config('system', 'mobile_theme', $theme_mobile);
|
||||
// }
|
||||
// set_config('system','site_channel', $site_channel);
|
||||
set_config('system','maximagesize', $maximagesize);
|
||||
|
||||
set_config('system','register_policy', $register_policy);
|
||||
set_config('system','register_wo_email', $register_wo_email);
|
||||
set_config('system','minimum_age', $minimum_age);
|
||||
set_config('system','invitation_only', $invite_only);
|
||||
set_config('system','auto_channel_create', $reg_autochannel);
|
||||
set_config('system', 'invitation_only', $invitation_only);
|
||||
set_config('system', 'invitation_also', $invitation_also);
|
||||
set_config('system','access_policy', $access_policy);
|
||||
set_config('system','account_abandon_days', $abandon_days);
|
||||
set_config('system','register_text', $register_text);
|
||||
@@ -153,6 +214,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);
|
||||
@@ -256,6 +320,8 @@ class Site {
|
||||
REGISTER_APPROVE => t("Yes - with approval"),
|
||||
REGISTER_OPEN => t("Yes")
|
||||
);
|
||||
$this->register_duty = get_config('system', 'register_duty', '-:-');
|
||||
$register_perday = get_config('system','max_daily_registrations', 50);
|
||||
|
||||
/* Acess policy */
|
||||
$access_choices = Array(
|
||||
@@ -282,9 +348,66 @@ class Site {
|
||||
$homelogin = get_config('system','login_on_homepage');
|
||||
$enable_context_help = get_config('system','enable_context_help');
|
||||
|
||||
// for reuse reg_delay and reg_expire
|
||||
$reg_rabots = array(
|
||||
'i' => t('Minute(s)'),
|
||||
'h' => t('Hour(s)') ,
|
||||
'd' => t('Day(s)') ,
|
||||
'w' => t('Week(s)') ,
|
||||
'm' => t('Month(s)') ,
|
||||
'y' => t('Year(s)')
|
||||
);
|
||||
$regdelay_n = $regdelay_u = false;
|
||||
$regdelay = get_config('system','register_delay');
|
||||
if ($regdelay)
|
||||
list($regdelay_n, $regdelay_u) = array(substr($regdelay,0,-1),substr($regdelay,-1));
|
||||
$reg_delay = replace_macros(get_markup_template('field_duration.qmc.tpl'),
|
||||
array(
|
||||
'label' => t('Register verification delay'),
|
||||
'qmc' => 'zar',
|
||||
'qmcid' => '',
|
||||
'help' => t('Time to wait before a registration can be verified'),
|
||||
'field' => array(
|
||||
'name' => 'delay',
|
||||
'title' => t('duration up from now'),
|
||||
'value' => ($regdelay_n === false ? 0 : $regdelay_n),
|
||||
'min' => '0',
|
||||
'max' => '99',
|
||||
'size' => '2',
|
||||
'default' => ($regdelay_u === false ? 'i' : $regdelay_u)
|
||||
),
|
||||
'rabot' => $reg_rabots
|
||||
)
|
||||
);
|
||||
$regexpire_n = $regexpire_u = false;
|
||||
$regexpire = get_config('system','register_expire');
|
||||
if ($regexpire)
|
||||
list($regexpire_n, $regexpire_u) = array(substr($regexpire,0,-1),substr($regexpire,-1));
|
||||
$reg_expire = replace_macros(get_markup_template('field_duration.qmc.tpl'),
|
||||
array(
|
||||
'label' => t('Register verification expiration time'),
|
||||
'qmc' => 'zar',
|
||||
'qmcid' => '',
|
||||
'help' => t('Time before an unverified registration will expire'),
|
||||
'field' => array(
|
||||
'name' => 'expire',
|
||||
'title' => t('duration up from now'),
|
||||
'value' => ($regexpire_n === false ? 3 : $regexpire_n),
|
||||
'min' => '0',
|
||||
'max' => '99',
|
||||
'size' => '2',
|
||||
'default' => ($regexpire_u === false ? 'd' : $regexpire_u)
|
||||
),
|
||||
'rabot' => $reg_rabots
|
||||
)
|
||||
);
|
||||
|
||||
$tao = '';
|
||||
$t = get_markup_template("admin_site.tpl");
|
||||
return replace_macros($t, array(
|
||||
'$title' => t('Administration'),
|
||||
// interfacing js vars
|
||||
'$tao' => $tao,
|
||||
'$page' => t('Site'),
|
||||
'$submit' => t('Submit'),
|
||||
'$registration' => t('Registration'),
|
||||
@@ -301,21 +424,87 @@ class Site {
|
||||
'$siteinfo' => array('siteinfo', t('Site Information'), get_config('system','siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode can be used here")),
|
||||
'$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices),
|
||||
'$theme' => array('theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - <a href='#' id='cnftheme'>change theme settings</a>"), $theme_choices),
|
||||
// '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
|
||||
// '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
|
||||
// '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
|
||||
// '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
|
||||
'$feed_contacts' => array('feed_contacts', t('Allow Feeds as Connections'),get_config('system','feed_contacts'),t('(Heavy system resource usage)')),
|
||||
'$maximagesize' => array('maximagesize', t("Maximum image size"), intval(get_config('system','maximagesize')), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")),
|
||||
'$register_policy' => array('register_policy', t("Does this site allow new member registration?"), get_config('system','register_policy'), "", $register_choices),
|
||||
'$invite_only' => array('invite_only', t("Invitation only"), get_config('system','invitation_only'), t("Only allow new member registrations with an invitation code. Above register policy must be set to Yes.")),
|
||||
'$minimum_age' => array('minimum_age', t("Minimum age"), (x(get_config('system','minimum_age'))?get_config('system','minimum_age'):13), t("Minimum age (in years) for who may register on this site.")),
|
||||
'$access_policy' => array('access_policy', t("Which best describes the types of account offered by this hub?"), get_config('system','access_policy'), t("This is displayed on the public server site list."), $access_choices),
|
||||
'$register_text' => array('register_text', t("Register text"), htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.")),
|
||||
|
||||
// Register
|
||||
// [hilmar->
|
||||
'$register_text' => [
|
||||
'register_text',
|
||||
t("Register text"),
|
||||
htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'),
|
||||
t("This text will be displayed prominently at the registration page")
|
||||
],
|
||||
'$register_policy' => [
|
||||
'register_policy',
|
||||
t("Does this site allow new member registration?"),
|
||||
get_config('system','register_policy'),
|
||||
"",
|
||||
$register_choices,
|
||||
],
|
||||
'$register_duty' => [
|
||||
'register_duty',
|
||||
t('Configure the registration open days/hours'),
|
||||
get_config('system', 'register_duty', '-:-'),
|
||||
t('Empty or \'-:-\' value will keep registration open 24/7 (default)') . EOL .
|
||||
t('Weekdays and hours must be separated by colon \':\', From-To ranges with a dash `-` example: 1:800-1200') . EOL .
|
||||
t('Weekday:Hour pairs must be separated by space \' \' example: 1:900-1700 2:900-1700') . EOL .
|
||||
t('From-To ranges must be separated by comma \',\' example: 1:800-1200,1300-1700 or 1-2,4-5:900-1700') . EOL .
|
||||
t('Advanced examples:') . ' 1-5:0900-1200,1300-1700 6:900-1230 ' . t('or') . ' 1-2,4-5:800-1800<br>' . EOL .
|
||||
'<a id="zar083a" class="btn btn-sm btn-outline-secondary zuia">' . t('Check your configuration') . '</a>'. EOL
|
||||
],
|
||||
'$register_perday' => [
|
||||
'register_perday',
|
||||
t('Max account registrations per day'),
|
||||
get_config('system', 'max_daily_registrations', 50),
|
||||
t('Unlimited if zero or no value - default 50')
|
||||
],
|
||||
'$register_sameip' => [
|
||||
'register_sameip',
|
||||
t('Max account registrations from same IP'),
|
||||
get_config('system', 'register_sameip', 3),
|
||||
t('Unlimited if zero or no value - default 3')
|
||||
],
|
||||
'$reg_delay' => $reg_delay,
|
||||
'$reg_expire' => $reg_expire,
|
||||
'$reg_autochannel' => [
|
||||
'auto_channel_create',
|
||||
t("Auto channel create"),
|
||||
get_config('system','auto_channel_create', 1),
|
||||
t("If disabled the channel will be created in a separate step during the registration process")
|
||||
],
|
||||
'$invitation_only' => [
|
||||
'invitation_only',
|
||||
t("Require invite code"),
|
||||
get_config('system', 'invitation_only', 0)
|
||||
],
|
||||
'$invitation_also' => [
|
||||
'invitation_also',
|
||||
t("Allow invite code"),
|
||||
get_config('system', 'invitation_also', 0)
|
||||
],
|
||||
'$verify_email' => [
|
||||
'verify_email',
|
||||
t("Require email address"),
|
||||
get_config('system','verify_email'),
|
||||
t("The provided email address will be verified (recommended)")
|
||||
],
|
||||
'$abandon_days' => [
|
||||
'abandon_days',
|
||||
t('Abandon account after x days'),
|
||||
get_config('system','account_abandon_days'),
|
||||
t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')
|
||||
],
|
||||
// <-hilmar]
|
||||
|
||||
'$role' => $role,
|
||||
'$frontpage' => array('frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'pubstream' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.")),
|
||||
'$mirror_frontpage' => array('mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting')),
|
||||
'$abandon_days' => array('abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')),
|
||||
'$allowed_sites' => array('allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")),
|
||||
'$verify_email' => array('verify_email', t("Verify Email Addresses"), get_config('system','verify_email'), t("Check to verify email addresses used in account registration (recommended).")),
|
||||
'$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.")),
|
||||
'$disable_discover_tab' => array('disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.')),
|
||||
'$site_firehose' => array('site_firehose', t('Site only Public Streams'), get_config('system','site_firehose'), t('Allow access to public content originating only from this site if Imported Public Streams are disabled.')),
|
||||
@@ -333,6 +522,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,19 +532,187 @@ 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)), ''),
|
||||
|
||||
'$sellpage' => array('site_sellpage', t('Public servers: Optional landing (marketing) webpage for new registrants'), get_config('system','sellpage',''), sprintf( t('Create this page first. Default is %s/register'),z_root())),
|
||||
'$first_page' => array('first_page', t('Page to display after creating a new channel'), get_config('system','workflow_channel_next','profiles'), t('Default: profiles')),
|
||||
|
||||
'$location' => array('site_location', t('Optional: site location'), get_config('system','site_location',''), t('Region or country')),
|
||||
|
||||
|
||||
'$form_security_token' => get_form_security_token("admin_site"),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Admin page site common post submit and ajax interaction
|
||||
* @author hilmar runge
|
||||
* @since 2020-02-04
|
||||
* Configure register office duty weekdays and hours
|
||||
* Syntax: weekdays:hours [weekdays:hours]
|
||||
* [.d[,d-d.]]]:hhmm-hhmm[,hhmm-hhmm...]
|
||||
* ranges are between blanks, days are 1-7, where 1 = Monday
|
||||
* hours are [h]hmm 3-4digit 24 clock values
|
||||
* ie 0900-1200,1300-1800 for hours
|
||||
* ie 1-2,4,5 for weekdays
|
||||
* ie 1-2:900-1800 monday and tuesday open from 9 to 18h
|
||||
*
|
||||
* @var $register_duty is the input field from the admin -> site page
|
||||
* @return the results are in the class vars $error, $msgbg and $jsoo
|
||||
* $jsoo is
|
||||
*/
|
||||
|
||||
// 3-4 digit 24h clock regex
|
||||
const regxTime34 = '/^(?:2[0-3]|[01][0-9]|[0-9])[0-5][0-9]$/';
|
||||
var $wdconst = array('','mo','tu','we','th','fr','sa','so');
|
||||
|
||||
// in
|
||||
var $register_duty;
|
||||
// intermediate
|
||||
var $isajax;
|
||||
// return
|
||||
var $jsoo;
|
||||
var $msgbg;
|
||||
var $error = 0;
|
||||
var $msgfg = '';
|
||||
|
||||
private function duty() {
|
||||
|
||||
$aro=array_fill(1, 7, 0);
|
||||
|
||||
if ($this->isajax) {
|
||||
$op = (preg_match('/[a-z]{2,4}/', $_REQUEST['zarop'])) ? $_REQUEST['zarop'] : '';
|
||||
if ($op == 'zar083') {
|
||||
$this->msgbg = 'Testmode:' . $this->eol . $this->msgbg;
|
||||
} else {
|
||||
killme();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$ranges = preg_split('/\s+/', $this->register_duty);
|
||||
$this->msgbg .= '..ranges: ' . print_r(count($ranges),true) . $this->eol;
|
||||
|
||||
foreach ($ranges as $rn => $range) {
|
||||
list($ws,$hs,) = explode(':', $range);
|
||||
|
||||
$ws ? $arw = explode( ',', $ws) : $arw=array();
|
||||
$this->msgbg .= ($rn+1).'.weekday ranges: ' . count($arw) . $this->eol;
|
||||
// $this->msgbg .= print_r($arw,true);
|
||||
$hs ? $arh = explode( ',', $hs) : $arh=array();
|
||||
$this->msgbg .= ($rn+1).'.hour ranges: ' . count($arh) . $this->eol;
|
||||
|
||||
$this->msgbg .= ($rn+1).'.wdays: ' . ( $ws ? print_r($ws,true) : 'none') . ' : '
|
||||
. ' hours: ' . print_r($hs,true) . $this->eol;
|
||||
|
||||
// several hs may belog to one wd
|
||||
// aro[0] is tmp store
|
||||
foreach ($arh as $hs) {
|
||||
list($ho,$hc,) = explode( '-', $hs );
|
||||
|
||||
// no value forces open very early, and be sure having valid hhmm values
|
||||
!$ho ? $ho = "0000" : '';
|
||||
!$hc ? $hc = "0000" : ''; // pseudo
|
||||
if (preg_match(self::regxTime34, $ho)
|
||||
&& preg_match(self::regxTime34, $hc)) {
|
||||
|
||||
// fix pseudo, allow no reverse range
|
||||
$hc == "0000" || $ho > $hc ? $hc = "2400" : '';
|
||||
|
||||
$aro[0][$ho] = 0;
|
||||
$aro[0][$hc] = 1;
|
||||
|
||||
$this->msgbg .= ($ho ? ' .open:' . $ho : '') . ($hc ? ' close:' . $hc : '') .$this->eol;
|
||||
} else {
|
||||
$this->msgbg .= ' .' . t('Invalid 24h time value (hhmm/hmm)') . $this->eol;
|
||||
$this->msgfg .= ' .ZAR0132E,' . t('Invalid 24h time value (hhmm/hmm)') . $this->eol;
|
||||
$this->error++;
|
||||
}
|
||||
}
|
||||
|
||||
// the weekday(s) values or ranges
|
||||
foreach ($arw as $ds) {
|
||||
$wd=explode('-', $ds);
|
||||
array_key_exists("1", $wd) && $wd[1]=="" ? $wd[1] = "7" : ''; // a case 3-
|
||||
array_key_exists("1", $wd) && $wd[0]=="" ? $wd[0] = "1" : ''; // a case -3
|
||||
!array_key_exists("1", $wd) ? $wd[1] = $wd[0] : ''; // a case 3
|
||||
if ($wd[0] > $wd[1]) continue; // reverse order will be ignored // a case 5-3
|
||||
if (preg_match('/^[1-7]{1}$/', $wd[0])) {
|
||||
if (preg_match('/^[1-7]{1}$/', $wd[1])) {
|
||||
// $this->msgbg .= print_r($wd,true);
|
||||
for ($i=$wd[0]; $i<=$wd[1]; $i++) {
|
||||
// take the tmp store for the selected day(s)
|
||||
$aro[$i]=$aro[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//$this->msgbg .= 'aro0: ' . print_r($aro,true) . $this->eol; // 4devels
|
||||
// clear the tmp store
|
||||
$aro[0]=array();
|
||||
}
|
||||
// discart the tmp store
|
||||
unset($aro[0]);
|
||||
// not configured days close at the beginning 0000h
|
||||
for ($i=1;$i<=7;$i++) { is_array($aro[$i]) ? '' : $aro[$i] = array("0000" => 1); }
|
||||
// $this->msgbg .= 'aro: ' . print_r($aro,true) . $this->eol; // 4devels
|
||||
|
||||
if ($this->isajax) {
|
||||
// tell what we have
|
||||
// $this->msgbg .= 'aro0: ' . print_r($aro,true) . $this->eol; // 4devels
|
||||
$this->msgbg .= 'Duty time table:' . $this->eol;
|
||||
foreach ($aro as $dow => $hrs) {
|
||||
$this->msgbg .= ' ' . $this->wdconst[$dow] . ' ';
|
||||
// $this->msgbg .= '**' . print_r($hrs,true);
|
||||
foreach ($hrs as $h => $o) {
|
||||
$this->msgbg .= ((!$o) ? $h . ':open' : $h . ':close') . ', ';
|
||||
}
|
||||
$this->msgbg = rtrim($this->msgbg, ', ') . $this->eol;
|
||||
}
|
||||
|
||||
$this->msgbg .= 'Generating 6 random times to check duty hours: ' . $this->eol;
|
||||
// we only need some random dates from anyway in past or future
|
||||
// because only the weekday and the clock is to test
|
||||
for ($i=0; $i<6; $i++) {
|
||||
$adow = rand(1, 7); // 1 to 7 (days)
|
||||
$cdow = $this->wdconst[$adow];
|
||||
// below is the essential algo to verify a date (of format Hi) meets an open or closed condition
|
||||
$t = date('Hi', ( rand(time(), 60*60*24+time()) ) );
|
||||
$how='close';
|
||||
foreach ($aro[$adow] as $o => $v) {
|
||||
// $this->msgbg .= 'debug: ' . $o . ' gt ' . $t . ' / ' . $v . $this->eol; // 4devels
|
||||
if ($o > $t) {
|
||||
$how = ($v ? 'open' : 'close');
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now we know
|
||||
$this->msgbg .= ' ' . $cdow . '.' . $t . '=' . $how . ', ';
|
||||
}
|
||||
$this->msgbg = rtrim($this->msgbg, ', ') . $this->eol;
|
||||
}
|
||||
|
||||
/*
|
||||
//$jov1 = array( 'view1' => $aro, 'view2' => '');
|
||||
$jov2=array();
|
||||
foreach ($aro as $d => $ts) {
|
||||
foreach ($ts as $t => $ft) {
|
||||
$jov2['view2'][$ft][] = $d.$t;
|
||||
//$ft=="1" && $t=="0000" ? $jov2['view2']["0"][] = $d."2400" : '';
|
||||
}
|
||||
}
|
||||
$this->msgbg .= print_r($jov2, true) . $this->eol; // 4devels
|
||||
*/
|
||||
|
||||
$this->joo = json_encode($aro);
|
||||
// $this->msgbg .= $this->joo . $this->eol; // 4devels
|
||||
// $this->msgbg .= print_r($aro, true) . $this->eol; // 4devels
|
||||
$okko = (json_decode($this->joo, true) ? true : false);
|
||||
if (!$okko) {
|
||||
$this->msgbg .= 'ZAR0139D,json 4 duty KO crash' . $this->eol;
|
||||
$this->msgfg .= 'ZAR0139D,json 4 duty KO crash' . $this->eol;
|
||||
$this->error++;
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,11 @@ class Apschema extends \Zotlabs\Web\Controller {
|
||||
'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'
|
||||
@@ -40,8 +44,13 @@ class Apschema extends \Zotlabs\Web\Controller {
|
||||
],
|
||||
|
||||
'ostatus' => 'http://ostatus.org#',
|
||||
'conversation' => 'ostatus:conversation'
|
||||
'conversation' => 'ostatus:conversation',
|
||||
|
||||
'diaspora' => 'https://diasporafoundation.org/ns/',
|
||||
'guid' => 'diaspora:guid',
|
||||
|
||||
'Hashtag' => 'as:Hashtag'
|
||||
|
||||
]
|
||||
];
|
||||
|
||||
@@ -54,4 +63,4 @@ class Apschema extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,9 +63,9 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
|
||||
if ($catsenabled){
|
||||
$itm = fetch_post_tags($itm);
|
||||
|
||||
|
||||
$cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
|
||||
|
||||
|
||||
foreach ($cats as $cat) {
|
||||
if (strlen($category))
|
||||
$category .= ', ';
|
||||
@@ -87,8 +87,6 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
|
||||
$content = $itm[0]['body'];
|
||||
|
||||
|
||||
|
||||
$rp = 'articles/' . $channel['channel_address'];
|
||||
|
||||
$x = array(
|
||||
@@ -114,6 +112,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
'post_id' => $post_id,
|
||||
'visitor' => true,
|
||||
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
||||
'summary' => htmlspecialchars($itm[0]['summary'],ENT_COMPAT,'UTF-8'),
|
||||
'placeholdertitle' => t('Title (optional)'),
|
||||
'pagetitle' => $card_title,
|
||||
'profile_uid' => (intval($channel['channel_id'])),
|
||||
|
||||
@@ -9,12 +9,13 @@ 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 {
|
||||
|
||||
function init() {
|
||||
|
||||
|
||||
if(argc() > 1)
|
||||
$which = argv(1);
|
||||
|
||||
@@ -27,13 +28,13 @@ class Articles extends Controller {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
profile_load($which);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function get($update = 0, $load = false) {
|
||||
|
||||
|
||||
if(observer_prohibited(true)) {
|
||||
return login();
|
||||
}
|
||||
@@ -55,7 +56,7 @@ class Articles extends Controller {
|
||||
|
||||
nav_set_selected('Articles');
|
||||
|
||||
head_add_link([
|
||||
head_add_link([
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/json+oembed',
|
||||
'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string),
|
||||
@@ -64,7 +65,7 @@ class Articles extends Controller {
|
||||
|
||||
|
||||
$category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : '');
|
||||
|
||||
|
||||
if($category) {
|
||||
$sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $category, TERM_CATEGORY));
|
||||
}
|
||||
@@ -73,24 +74,24 @@ class Articles extends Controller {
|
||||
$datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : '');
|
||||
|
||||
$which = argv(1);
|
||||
|
||||
|
||||
$selected_card = ((argc() > 2) ? argv(2) : '');
|
||||
|
||||
$_SESSION['return_url'] = App::$query_string;
|
||||
|
||||
|
||||
$uid = local_channel();
|
||||
$owner = App::$profile_uid;
|
||||
$observer = App::get_observer();
|
||||
|
||||
|
||||
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
|
||||
|
||||
|
||||
if(! perm_is_allowed($owner,$ob_hash,'view_pages')) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$is_owner = ($uid && $uid == $owner);
|
||||
|
||||
|
||||
$channel = channelx_by_n($owner);
|
||||
|
||||
if($channel) {
|
||||
@@ -104,7 +105,7 @@ class Articles extends Controller {
|
||||
else {
|
||||
$channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if(perm_is_allowed($owner,$ob_hash,'write_pages')) {
|
||||
@@ -113,16 +114,15 @@ class Articles extends Controller {
|
||||
'webpage' => ITEM_TYPE_ARTICLE,
|
||||
'is_owner' => true,
|
||||
'content_label' => t('Add Article'),
|
||||
'button' => t('Create'),
|
||||
'button' => t('Save'),
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|
||||
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|
||||
|| $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
|
||||
'acl' => (($is_owner) ? populate_acl($channel_acl, false,
|
||||
'acl' => (($is_owner) ? populate_acl($channel_acl, false,
|
||||
PermissionDescription::fromGlobalPermission('view_pages')) : ''),
|
||||
'permissions' => $channel_acl,
|
||||
'showacl' => (($is_owner) ? true : false),
|
||||
'visitor' => true,
|
||||
'body' => '[summary][/summary]',
|
||||
'hide_location' => false,
|
||||
'hide_voting' => false,
|
||||
'profile_uid' => intval($owner),
|
||||
@@ -146,12 +146,12 @@ class Articles extends Controller {
|
||||
else {
|
||||
$editor = '';
|
||||
}
|
||||
|
||||
|
||||
$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']));
|
||||
|
||||
|
||||
|
||||
$sql_extra = item_permissions_sql($owner);
|
||||
$sql_item = '';
|
||||
|
||||
@@ -175,8 +175,8 @@ class Articles extends Controller {
|
||||
$sql_extra2 .= " and item.item_thread_top != 0 ";
|
||||
}
|
||||
|
||||
$r = q("select * from item
|
||||
where item.uid = %d and item_type = %d
|
||||
$r = q("select * from item
|
||||
where item.uid = %d and item_type = %d
|
||||
$sql_extra $sql_extra2 $sql_item order by item.created desc $pager_sql",
|
||||
intval($owner),
|
||||
intval(ITEM_TYPE_ARTICLE)
|
||||
@@ -192,7 +192,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,17 +200,20 @@ 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))
|
||||
$page_mode = 'pager_list';
|
||||
else
|
||||
|
||||
@@ -1,61 +1,188 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use ZipArchive;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Verify;
|
||||
|
||||
require_once('include/security.php');
|
||||
require_once('include/attach.php');
|
||||
|
||||
class Attach extends Controller {
|
||||
|
||||
class Attach extends \Zotlabs\Web\Controller {
|
||||
function post() {
|
||||
|
||||
function init() {
|
||||
|
||||
if(argc() < 2) {
|
||||
notice( t('Item not available.') . EOL);
|
||||
$attach_ids = ((x($_REQUEST, 'attach_ids')) ? $_REQUEST['attach_ids'] : []);
|
||||
$attach_path = ((x($_REQUEST, 'attach_path')) ? $_REQUEST['attach_path'] : '');
|
||||
$channel_id = ((x($_REQUEST, 'channel_id')) ? intval($_REQUEST['channel_id']) : 0);
|
||||
$channel = channelx_by_n($channel_id);
|
||||
|
||||
if (!$channel) {
|
||||
notice(t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$r = attach_by_hash(argv(1),get_observer_hash(),((argc() > 2) ? intval(argv(2)) : 0));
|
||||
|
||||
if(! $r['success']) {
|
||||
notice( $r['message'] . EOL);
|
||||
|
||||
$strip_str = '/cloud/' . $channel['channel_address'] . '/';
|
||||
$count = strlen($strip_str);
|
||||
$attach_path = substr($attach_path, $count);
|
||||
|
||||
if ($attach_ids) {
|
||||
|
||||
$zip_dir = 'store/[data]/' . $channel['channel_address'] . '/tmp';
|
||||
if (!is_dir($zip_dir))
|
||||
mkdir($zip_dir, STORAGE_DEFAULT_PERMISSIONS, true);
|
||||
|
||||
$token = random_string(32);
|
||||
|
||||
$zip_file = 'download_' . $token . '.zip';
|
||||
$zip_path = $zip_dir . '/' . $zip_file;
|
||||
|
||||
$zip = new ZipArchive();
|
||||
|
||||
if ($zip->open($zip_path, ZipArchive::CREATE) === true) {
|
||||
|
||||
$zip_filename = self::zip_archive_handler($zip, $attach_ids, $attach_path);
|
||||
|
||||
$zip->close();
|
||||
|
||||
$meta = [
|
||||
'zip_filename' => $zip_filename,
|
||||
'zip_path' => $zip_path
|
||||
];
|
||||
|
||||
Verify::create('zip_token', 0, $token, json_encode($meta));
|
||||
|
||||
json_return_and_die([
|
||||
'success' => true,
|
||||
'token' => $token
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function get() {
|
||||
|
||||
if (argc() < 2) {
|
||||
notice(t('Item not available.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$token = ((x($_REQUEST, 'token')) ? $_REQUEST['token'] : '');
|
||||
|
||||
if (argv(1) === 'download') {
|
||||
$meta = Verify::get_meta('zip_token', 0, $token);
|
||||
|
||||
if (!$meta)
|
||||
killme();
|
||||
|
||||
$meta = json_decode($meta, true);
|
||||
|
||||
header('Content-Type: application/zip');
|
||||
header('Content-Disposition: attachment; filename="' . $meta['zip_filename'] . '"');
|
||||
header('Content-Length: ' . filesize($meta['zip_path']));
|
||||
|
||||
$istream = fopen($meta['zip_path'], 'rb');
|
||||
$ostream = fopen('php://output', 'wb');
|
||||
if ($istream && $ostream) {
|
||||
pipe_streams($istream, $ostream);
|
||||
fclose($istream);
|
||||
fclose($ostream);
|
||||
}
|
||||
|
||||
unlink($meta['zip_path']);
|
||||
killme();
|
||||
}
|
||||
|
||||
$r = attach_by_hash(argv(1), get_observer_hash(), ((argc() > 2) ? intval(argv(2)) : 0));
|
||||
|
||||
if (!$r['success']) {
|
||||
notice($r['message'] . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$c = q("select channel_address from channel where channel_id = %d limit 1",
|
||||
intval($r['data']['uid'])
|
||||
);
|
||||
|
||||
if(! $c)
|
||||
|
||||
if (!$c)
|
||||
return;
|
||||
|
||||
|
||||
$unsafe_types = array('text/html','text/css','application/javascript');
|
||||
|
||||
if(in_array($r['data']['filetype'],$unsafe_types) && (! channel_codeallowed($r['data']['uid']))) {
|
||||
header('Content-type: text/plain');
|
||||
|
||||
$unsafe_types = array('text/html', 'text/css', 'application/javascript');
|
||||
|
||||
if (in_array($r['data']['filetype'], $unsafe_types) && (!channel_codeallowed($r['data']['uid']))) {
|
||||
header('Content-Type: text/plain');
|
||||
}
|
||||
else {
|
||||
header('Content-type: ' . $r['data']['filetype']);
|
||||
header('Content-Type: ' . $r['data']['filetype']);
|
||||
}
|
||||
|
||||
header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"');
|
||||
if(intval($r['data']['os_storage'])) {
|
||||
$fname = dbunescbin($r['data']['content']);
|
||||
if(strpos($fname,'store') !== false)
|
||||
$istream = fopen($fname,'rb');
|
||||
|
||||
header('Content-Disposition: attachment; filename="' . $r['data']['filename'] . '"');
|
||||
if (intval($r['data']['os_storage'])) {
|
||||
$fname = $r['data']['content'];
|
||||
if (strpos($fname, 'store') !== false)
|
||||
$istream = fopen($fname, 'rb');
|
||||
else
|
||||
$istream = fopen('store/' . $c[0]['channel_address'] . '/' . $fname,'rb');
|
||||
$ostream = fopen('php://output','wb');
|
||||
if($istream && $ostream) {
|
||||
pipe_streams($istream,$ostream);
|
||||
$istream = fopen('store/' . $c[0]['channel_address'] . '/' . $fname, 'rb');
|
||||
$ostream = fopen('php://output', 'wb');
|
||||
if ($istream && $ostream) {
|
||||
pipe_streams($istream, $ostream);
|
||||
fclose($istream);
|
||||
fclose($ostream);
|
||||
}
|
||||
}
|
||||
else
|
||||
echo dbunescbin($r['data']['content']);
|
||||
echo $r['data']['content'];
|
||||
killme();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function zip_archive_handler($zip, $attach_ids, $attach_path, $pass = 1) {
|
||||
|
||||
$observer_hash = get_observer_hash();
|
||||
$single = ((count($attach_ids) == 1) ? true : false);
|
||||
$download_name = 'download.zip';
|
||||
|
||||
foreach ($attach_ids as $attach_id) {
|
||||
|
||||
$r = attach_by_id($attach_id, $observer_hash);
|
||||
|
||||
if (!$r['success']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($r['data']['is_dir'] && $single && $pass === 1)
|
||||
$download_name = $r['data']['filename'] . '.zip';
|
||||
|
||||
$zip_path = $r['data']['display_path'];
|
||||
|
||||
if ($attach_path) {
|
||||
$strip_str = $attach_path . '/';
|
||||
$count = strlen($strip_str);
|
||||
$zip_path = substr($r['data']['display_path'], $count);
|
||||
}
|
||||
|
||||
if ($r['data']['is_dir']) {
|
||||
$zip->addEmptyDir($zip_path);
|
||||
|
||||
$d = q("SELECT id FROM attach WHERE folder = '%s'",
|
||||
dbesc($r['data']['hash'])
|
||||
);
|
||||
|
||||
$attach_ids = ids_to_array($d);
|
||||
self::zip_archive_handler($zip, $attach_ids, $attach_path, $pass++);
|
||||
}
|
||||
else {
|
||||
$file_path = $r['data']['content'];
|
||||
$zip->addFile($file_path, $zip_path);
|
||||
// compressing can be ressource intensive - just store the data
|
||||
$zip->setCompressionName($zip_path, ZipArchive::CM_STORE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $download_name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
203
Zotlabs/Module/Attach_edit.php
Normal file
203
Zotlabs/Module/Attach_edit.php
Normal file
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
/**
|
||||
* @file Zotlabs/Module/Attach_edit.php
|
||||
*
|
||||
*/
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Access\AccessList;
|
||||
|
||||
class Attach_edit extends Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
if (!local_channel() && !remote_channel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attach_ids = ((x($_POST, 'attach_ids')) ? $_POST['attach_ids'] : []);
|
||||
$attach_id = ((x($_POST, 'attach_id')) ? intval($_POST['attach_id']) : 0);
|
||||
$channel_id = ((x($_POST, 'channel_id')) ? intval($_POST['channel_id']) : 0);
|
||||
$dnd = ((x($_POST, 'dnd')) ? intval($_POST['dnd']) : 0);
|
||||
$permissions = ((x($_POST, 'permissions')) ? intval($_POST['permissions']) : 0);
|
||||
$return_path = ((x($_POST, 'return_path')) ? notags($_POST['return_path']) : 'cloud');
|
||||
$delete = ((x($_POST, 'delete')) ? intval($_POST['delete']) : 0);
|
||||
$newfolder = ((x($_POST, 'newfolder_' . $attach_id)) ? notags($_POST['newfolder_' . $attach_id]) : '');
|
||||
if(! $newfolder)
|
||||
$newfolder = ((x($_POST, 'newfolder')) ? notags($_POST['newfolder']) : '');
|
||||
$newfilename = ((x($_POST, 'newfilename_' . $attach_id)) ? notags($_POST['newfilename_' . $attach_id]) : '');
|
||||
$recurse = ((x($_POST, 'recurse_' . $attach_id)) ? intval($_POST['recurse_' . $attach_id]) : 0);
|
||||
if(! $recurse)
|
||||
$recurse = ((x($_POST, 'recurse')) ? intval($_POST['recurse']) : 0);
|
||||
$notify = ((x($_POST, 'notify_edit_' . $attach_id)) ? intval($_POST['notify_edit_' . $attach_id]) : 0);
|
||||
$copy = ((x($_POST, 'copy_' . $attach_id)) ? intval($_POST['copy_' . $attach_id]) : 0);
|
||||
if(! $copy)
|
||||
$copy = ((x($_POST, 'copy')) ? intval($_POST['copy']) : 0);
|
||||
|
||||
$categories = ((x($_POST, 'categories_' . $attach_id)) ? notags($_POST['categories_' . $attach_id]) : '');
|
||||
if(! $categories)
|
||||
$categories = ((x($_POST, 'categories')) ? notags($_POST['categories']) : '');
|
||||
|
||||
if($attach_id)
|
||||
$attach_ids[] = $attach_id;
|
||||
|
||||
$single = ((count($attach_ids) === 1) ? true : false);
|
||||
|
||||
$channel = channelx_by_n($channel_id);
|
||||
|
||||
if (! $channel) {
|
||||
notice(t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$nick = $channel['channel_address'];
|
||||
$observer = App::get_observer();
|
||||
$observer_hash = (($observer) ? $observer['xchan_hash'] : '');
|
||||
$is_owner = ((local_channel() == $channel_id) ? true : false);
|
||||
|
||||
$ids_str = implode(',', $attach_ids);
|
||||
|
||||
$r = q("SELECT id, uid, hash, creator, folder, filename, is_photo, is_dir FROM attach WHERE id IN ( %s ) AND uid = %d",
|
||||
dbesc($ids_str),
|
||||
intval($channel_id)
|
||||
);
|
||||
|
||||
if (! $r) {
|
||||
notice(t('File not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($r as $rr) {
|
||||
$actions_done = '';
|
||||
$attach_id = $rr['id'];
|
||||
$resource = $rr['hash'];
|
||||
$creator = $rr['creator'];
|
||||
$folder = $rr['folder'];
|
||||
$filename = $rr['filename'];
|
||||
$is_photo = intval($rr['is_photo']);
|
||||
$is_dir = intval($rr['is_dir']);
|
||||
$admin_delete = false;
|
||||
|
||||
$is_creator = (($creator == $observer_hash) ? true : false);
|
||||
$move = ((! $copy && ($folder !== $newfolder || (($single) ? $filename !== $newfilename : false))) ? true : false);
|
||||
|
||||
$perms = get_all_perms($channel_id, $observer_hash);
|
||||
|
||||
if (! ($perms['view_storage'] || is_site_admin())) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $perms['write_storage']) {
|
||||
if (is_site_admin()) {
|
||||
$admin_delete = true;
|
||||
}
|
||||
else {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$is_owner && !$admin_delete) {
|
||||
if(! $is_creator) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($delete) {
|
||||
attach_delete($channel_id, $resource, $is_photo);
|
||||
$actions_done .= 'delete,';
|
||||
}
|
||||
|
||||
if ($copy) {
|
||||
if($is_dir && $resource == $newfolder) {
|
||||
notice( t('Can not copy folder into itself.') . EOL);
|
||||
continue;
|
||||
}
|
||||
$x = attach_copy($channel_id, $resource, $newfolder, (($single) ? $newfilename : ''));
|
||||
if ($x['success'])
|
||||
$resource = $x['resource_id'];
|
||||
|
||||
$actions_done .= 'copy,';
|
||||
|
||||
}
|
||||
|
||||
if ($move) {
|
||||
if($is_dir && $resource == $newfolder) {
|
||||
notice( sprintf(t('Can not move folder "%s" into itself.'), $filename) . EOL);
|
||||
continue;
|
||||
}
|
||||
$x = attach_move($channel_id, $resource, $newfolder, (($single) ? $newfilename : ''));
|
||||
|
||||
$actions_done .= 'move,';
|
||||
|
||||
}
|
||||
|
||||
if(! $delete && ! $dnd) {
|
||||
if ($single || (! $single && $categories)) {
|
||||
q("DELETE FROM term WHERE uid = %d AND oid = %d AND otype = %d",
|
||||
intval($channel_id),
|
||||
intval($attach_id),
|
||||
intval(TERM_OBJ_FILE)
|
||||
);
|
||||
$cat = explode(',', $categories);
|
||||
if ($cat) {
|
||||
foreach($cat as $term) {
|
||||
$term = trim(escape_tags($term));
|
||||
if ($term) {
|
||||
$term_link = z_root() . '/cloud/' . $nick . '/?cat=' . $term;
|
||||
store_item_tag($channel_id, $attach_id, TERM_OBJ_FILE, TERM_CATEGORY, $term, $term_link);
|
||||
}
|
||||
}
|
||||
$actions_done .= 'cat_add,';
|
||||
}
|
||||
}
|
||||
else {
|
||||
q("DELETE FROM term WHERE uid = %d AND oid = %d AND otype = %d",
|
||||
intval($channel_id),
|
||||
intval($attach_id),
|
||||
intval(TERM_OBJ_FILE)
|
||||
);
|
||||
$actions_done .= 'cat_remove,';
|
||||
}
|
||||
|
||||
if ($is_owner && ($single || (! $single && $permissions))) {
|
||||
$acl = new AccessList($channel);
|
||||
$acl->set_from_array($_REQUEST);
|
||||
$x = $acl->get();
|
||||
|
||||
attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true);
|
||||
$actions_done .= 'permissions,';
|
||||
|
||||
if ($notify) {
|
||||
attach_store_item($channel, $observer, $resource);
|
||||
$actions_done .= 'notify,';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! $admin_delete && $actions_done) {
|
||||
$sync = attach_export_data($channel, $resource, (($delete) ? true : false));
|
||||
|
||||
if ($sync) {
|
||||
Libsync::build_sync_packet($channel_id, ['file' => [$sync]]);
|
||||
}
|
||||
}
|
||||
|
||||
logger('attach_edit: ' . $actions_done);
|
||||
|
||||
}
|
||||
|
||||
if($dnd || $delete) {
|
||||
json_return_and_die([ 'success' => true ]);
|
||||
}
|
||||
|
||||
goaway($return_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +1,38 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/zot.php');
|
||||
|
||||
|
||||
class Authtest extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
|
||||
|
||||
|
||||
$auth_success = false;
|
||||
$o .= '<h3>Magic-Auth Diagnostic</h3>';
|
||||
|
||||
|
||||
if(! local_channel()) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
$o .= '<form action="authtest" method="get">';
|
||||
$o .= 'Target URL: <input type="text" style="width: 250px;" name="dest" value="' . $_GET['dest'] .'" />';
|
||||
$o .= '<input type="submit" name="submit" value="Submit" /></form>';
|
||||
|
||||
$o .= '<input type="submit" name="submit" value="Submit" /></form>';
|
||||
|
||||
$o .= '<br /><br />';
|
||||
|
||||
|
||||
if(x($_GET,'dest')) {
|
||||
if(strpos($_GET['dest'],'@')) {
|
||||
$_GET['dest'] = $_REQUEST['dest'] = 'https://' . substr($_GET['dest'],strpos($_GET['dest'],'@')+1) . '/channel/' . substr($_GET['dest'],0,strpos($_GET['dest'],'@'));
|
||||
}
|
||||
|
||||
|
||||
$_REQUEST['test'] = 1;
|
||||
$mod = new Magic();
|
||||
$x = $mod->init($a);
|
||||
|
||||
$o .= 'Local Setup returns: ' . print_r($x,true);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if($x['url']) {
|
||||
$z = z_fetch_url($x['url'] . '&test=1');
|
||||
if($z['success']) {
|
||||
@@ -50,12 +47,12 @@ class Authtest extends \Zotlabs\Web\Controller {
|
||||
$o .= 'fetch url failure.' . print_r($z,true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(! $auth_success)
|
||||
$o .= 'Authentication Failed!' . EOL;
|
||||
}
|
||||
|
||||
|
||||
return str_replace("\n",'<br />',$o);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ class Bookmarks extends \Zotlabs\Web\Controller {
|
||||
|
||||
nav_set_selected('Bookmarks');
|
||||
|
||||
$item_id = intval($_REQUEST['item']);
|
||||
$burl = trim($_REQUEST['burl']);
|
||||
$item_id = (isset($_REQUEST['item']) ? $_REQUEST['item'] : false);
|
||||
$burl = (isset($_REQUEST['burl']) ? trim($_REQUEST['burl']) : '');
|
||||
|
||||
if(! $item_id)
|
||||
return;
|
||||
@@ -38,7 +38,7 @@ class Bookmarks extends \Zotlabs\Web\Controller {
|
||||
|
||||
$item = $i[0];
|
||||
|
||||
$terms = get_terms_oftype($item['term'],TERM_BOOKMARK);
|
||||
$terms = (x($item, 'term') ? get_terms_oftype($item['term'],TERM_BOOKMARK) : false);
|
||||
|
||||
if($terms) {
|
||||
require_once('include/bookmarks.php');
|
||||
|
||||
@@ -19,47 +19,45 @@ class Cal extends Controller {
|
||||
if(observer_prohibited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(argc() > 1) {
|
||||
$nick = argv(1);
|
||||
|
||||
|
||||
profile_load($nick);
|
||||
|
||||
|
||||
$channelx = channelx_by_nick($nick);
|
||||
|
||||
|
||||
if(! $channelx) {
|
||||
notice( t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
App::$data['channel'] = $channelx;
|
||||
|
||||
|
||||
$observer = App::get_observer();
|
||||
App::$data['observer'] = $observer;
|
||||
|
||||
$observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
|
||||
|
||||
|
||||
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>" ;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
|
||||
if(observer_prohibited()) {
|
||||
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')) {
|
||||
notice( t('Permissions denied.') . EOL);
|
||||
return;
|
||||
@@ -78,10 +76,10 @@ class Cal extends Controller {
|
||||
|
||||
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts') || App::$profile['hide_friends'])
|
||||
$sql_extra .= " and etype != 'birthday' ";
|
||||
|
||||
|
||||
$first_day = feature_enabled($channel['channel_id'], 'cal_first_day');
|
||||
$first_day = (($first_day) ? $first_day : 0);
|
||||
|
||||
|
||||
$start = '';
|
||||
$finish = '';
|
||||
|
||||
@@ -89,7 +87,7 @@ class Cal extends Controller {
|
||||
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);
|
||||
@@ -109,10 +107,10 @@ class Cal extends Controller {
|
||||
// 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' ))
|
||||
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),
|
||||
@@ -121,7 +119,7 @@ class Cal extends Controller {
|
||||
dbesc($adjust_finish)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$r = fetch_post_tags($r,true);
|
||||
@@ -129,20 +127,16 @@ class Cal extends Controller {
|
||||
}
|
||||
|
||||
$events = [];
|
||||
|
||||
|
||||
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'));
|
||||
$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($tz, date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
|
||||
$end = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
|
||||
}
|
||||
|
||||
$html = '';
|
||||
@@ -151,6 +145,10 @@ class Cal extends Controller {
|
||||
$html = format_event_html($rr);
|
||||
}
|
||||
|
||||
$tz = get_iconfig($rr, 'event', 'timezone');
|
||||
if(! $tz)
|
||||
$tz = 'UTC';
|
||||
|
||||
$events[] = array(
|
||||
'calendar_id' => 'channel_calendar',
|
||||
'rw' => true,
|
||||
@@ -159,14 +157,14 @@ class Cal extends Controller {
|
||||
'timezone' => $tz,
|
||||
'start'=> $start,
|
||||
'end' => $end,
|
||||
'drop' => $drop,
|
||||
'drop' => false,
|
||||
'allDay' => (($rr['adjust']) ? 0 : 1),
|
||||
'title' => htmlentities($rr['summary'], ENT_COMPAT, 'UTF-8', false),
|
||||
'editable' => $edit ? true : false,
|
||||
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
|
||||
'editable' => false,
|
||||
'item' => $rr,
|
||||
'plink' => [$rr['plink'], t('Link to source')],
|
||||
'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8', false),
|
||||
'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8', false),
|
||||
'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']),
|
||||
@@ -180,7 +178,7 @@ class Cal extends Controller {
|
||||
echo json_encode($events);
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
if (x($_GET,'id')) {
|
||||
$o = replace_macros(get_markup_template("cal_event.tpl"), [
|
||||
'$events' => $events
|
||||
@@ -205,14 +203,14 @@ class Cal extends Controller {
|
||||
'$prev' => t('Previous'),
|
||||
'$next' => t('Next'),
|
||||
'$today' => t('Today'),
|
||||
'$title' => $title,
|
||||
'$dtstart' => $dtstart,
|
||||
'$dtend' => $dtend,
|
||||
'$title' => '',
|
||||
'$dtstart' => '',
|
||||
'$dtend' => '',
|
||||
'$nick' => $nick
|
||||
]);
|
||||
|
||||
return $o;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -63,9 +63,9 @@ class Card_edit extends \Zotlabs\Web\Controller {
|
||||
|
||||
if ($catsenabled){
|
||||
$itm = fetch_post_tags($itm);
|
||||
|
||||
|
||||
$cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
|
||||
|
||||
|
||||
foreach ($cats as $cat) {
|
||||
if (strlen($category))
|
||||
$category .= ', ';
|
||||
@@ -114,6 +114,7 @@ class Card_edit extends \Zotlabs\Web\Controller {
|
||||
'post_id' => $post_id,
|
||||
'visitor' => true,
|
||||
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
||||
'summary' => htmlspecialchars($itm[0]['summary'],ENT_COMPAT,'UTF-8'),
|
||||
'placeholdertitle' => t('Title (optional)'),
|
||||
'pagetitle' => $card_title,
|
||||
'profile_uid' => (intval($channel['channel_id'])),
|
||||
|
||||
@@ -110,7 +110,7 @@ class Cards extends Controller {
|
||||
'webpage' => ITEM_TYPE_CARD,
|
||||
'is_owner' => true,
|
||||
'content_label' => t('Add Card'),
|
||||
'button' => t('Create'),
|
||||
'button' => t('Save'),
|
||||
'nickname' => $channel['channel_address'],
|
||||
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|
||||
|| $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
|
||||
@@ -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']));
|
||||
|
||||
|
||||
|
||||
@@ -4,11 +4,16 @@ namespace Zotlabs\Module;
|
||||
use App;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
|
||||
require_once('include/event.php');
|
||||
|
||||
require_once('include/auth.php');
|
||||
require_once('include/security.php');
|
||||
require_once('include/cdav.php');
|
||||
|
||||
class Cdav extends Controller {
|
||||
|
||||
@@ -41,15 +46,16 @@ class Cdav extends 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_id_url = '%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'])
|
||||
@@ -64,7 +70,7 @@ class Cdav extends 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;
|
||||
}
|
||||
@@ -129,7 +135,7 @@ class Cdav extends Controller {
|
||||
$auth = new \Zotlabs\Storage\BasicAuth();
|
||||
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'CalDAV/CardDAV');
|
||||
|
||||
if (local_channel()) {
|
||||
if(local_channel()) {
|
||||
|
||||
logger('loggedin');
|
||||
|
||||
@@ -147,15 +153,89 @@ class Cdav extends Controller {
|
||||
$auth->observer = $channel['channel_hash'];
|
||||
|
||||
$principalUri = 'principals/' . $channel['channel_address'];
|
||||
if(!cdav_principal($principalUri)) {
|
||||
if(! cdav_principal($principalUri)) {
|
||||
$this->activate($pdo, $channel);
|
||||
if(!cdav_principal($principalUri)) {
|
||||
if(! cdav_principal($principalUri)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Track CDAV updates from remote clients
|
||||
|
||||
$httpmethod = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
if($httpmethod === 'PUT' || $httpmethod === 'DELETE') {
|
||||
|
||||
$channel = channelx_by_nick(argv(2));
|
||||
$principalUri = 'principals/' . $channel['channel_address'];
|
||||
$httpuri = $_SERVER['REQUEST_URI'];
|
||||
|
||||
logger("debug: method: " . $httpmethod, LOGGER_DEBUG);
|
||||
logger("debug: uri: " . $httpuri, LOGGER_DEBUG);
|
||||
|
||||
if(strpos($httpuri, 'cdav/addressbooks') !== false) {
|
||||
$sync = 'addressbook';
|
||||
$cdavtable = 'addressbooks';
|
||||
}
|
||||
elseif(strpos($httpuri, 'cdav/calendars') !== false) {
|
||||
$sync = 'calendar';
|
||||
$cdavtable = 'calendarinstances';
|
||||
}
|
||||
else {
|
||||
$sync = false;
|
||||
}
|
||||
|
||||
if($sync) {
|
||||
|
||||
$uri = basename($httpuri);
|
||||
$httpbody = file_get_contents('php://input');
|
||||
|
||||
logger("debug: body: " . $httpbody, LOGGER_DEBUG);
|
||||
|
||||
if($x = get_cdav_id($principalUri, argv(3), $cdavtable)) {
|
||||
|
||||
$cdavdata = $this->get_cdav_data($x['id'], $cdavtable);
|
||||
$etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false);
|
||||
|
||||
// delete
|
||||
if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag) {
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
$sync => [
|
||||
'action' => 'delete_card',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'carduri' => $uri
|
||||
]
|
||||
]);
|
||||
}
|
||||
else {
|
||||
if($etag && $cdavdata['etag'] !== $etag) {
|
||||
// update
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
$sync => [
|
||||
'action' => 'update_card',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'carduri' => $uri,
|
||||
'card' => $httpbody
|
||||
]
|
||||
]);
|
||||
}
|
||||
else {
|
||||
// new
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
$sync => [
|
||||
'action' => 'import',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'ids' => [ $uri ],
|
||||
'card' => $httpbody
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo);
|
||||
$carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
|
||||
@@ -189,7 +269,7 @@ class Cdav extends Controller {
|
||||
|
||||
// Plugins
|
||||
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth));
|
||||
//$server->addPlugin(new \Sabre\DAV\Browser\Plugin());
|
||||
// $server->addPlugin(new \Sabre\DAV\Browser\Plugin());
|
||||
$server->addPlugin(new \Sabre\DAV\Sync\Plugin());
|
||||
$server->addPlugin(new \Sabre\DAV\Sharing\Plugin());
|
||||
$server->addPlugin(new \Sabre\DAVACL\Plugin());
|
||||
@@ -197,7 +277,7 @@ class Cdav extends Controller {
|
||||
// CalDAV plugins
|
||||
$server->addPlugin(new \Sabre\CalDAV\Plugin());
|
||||
$server->addPlugin(new \Sabre\CalDAV\SharingPlugin());
|
||||
//$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
|
||||
// $server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
|
||||
$server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
|
||||
|
||||
// CardDAV plugins
|
||||
@@ -205,7 +285,7 @@ class Cdav extends Controller {
|
||||
$server->addPlugin(new \Sabre\CardDAV\VCFExportPlugin());
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
||||
$server->start();
|
||||
|
||||
killme();
|
||||
|
||||
@@ -261,6 +341,14 @@ class Cdav extends Controller {
|
||||
|
||||
// set new calendar to be visible
|
||||
set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'calendar' => [
|
||||
'action' => 'create',
|
||||
'uri' => $calendarUri,
|
||||
'properties' => $properties
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
//create new calendar object via ajax request
|
||||
@@ -271,17 +359,19 @@ class Cdav extends Controller {
|
||||
if(!cdav_perms($id[0],$calendars,true))
|
||||
return;
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
$allday = $_REQUEST['allday'];
|
||||
|
||||
$title = $_REQUEST['title'];
|
||||
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
|
||||
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||
$dtstart = new \DateTime($start);
|
||||
|
||||
if($_REQUEST['dtend']) {
|
||||
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
|
||||
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||
$dtend = new \DateTime($end);
|
||||
}
|
||||
$description = $_REQUEST['description'];
|
||||
@@ -326,9 +416,17 @@ class Cdav extends Controller {
|
||||
$vcalendar->VEVENT->DTSTART['TZID'] = $tz;
|
||||
|
||||
$calendarData = $vcalendar->serialize();
|
||||
|
||||
$caldavBackend->createCalendarObject($id, $objectUri, $calendarData);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'calendar' => [
|
||||
'action' => 'import',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'ids' => [ $objectUri ],
|
||||
'card' => $calendarData
|
||||
]
|
||||
]);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -340,17 +438,24 @@ class Cdav extends Controller {
|
||||
if(! cdav_perms($id[0],$calendars))
|
||||
return;
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
|
||||
|
||||
$mutations = [
|
||||
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname'],
|
||||
'{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color']
|
||||
];
|
||||
|
||||
$patch = new \Sabre\DAV\PropPatch($mutations);
|
||||
|
||||
$caldavBackend->updateCalendar($id, $patch);
|
||||
|
||||
$patch->commit();
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'calendar' => [
|
||||
'action' => 'edit',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'mutations' => $mutations,
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
//edit calendar object via ajax request
|
||||
@@ -358,9 +463,11 @@ class Cdav extends Controller {
|
||||
|
||||
$id = explode(':', $_REQUEST['target']);
|
||||
|
||||
if(!cdav_perms($id[0],$calendars,true))
|
||||
if(! cdav_perms($id[0],$calendars,true))
|
||||
return;
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
@@ -368,10 +475,10 @@ class Cdav extends Controller {
|
||||
|
||||
$uri = $_REQUEST['uri'];
|
||||
$title = $_REQUEST['title'];
|
||||
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
|
||||
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||
$dtstart = new \DateTime($start);
|
||||
if($_REQUEST['dtend']) {
|
||||
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
|
||||
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||
$dtend = new \DateTime($end);
|
||||
}
|
||||
$description = $_REQUEST['description'];
|
||||
@@ -406,9 +513,17 @@ class Cdav extends Controller {
|
||||
$vcalendar->VEVENT->LOCATION = $location;
|
||||
|
||||
$calendarData = $vcalendar->serialize();
|
||||
|
||||
$caldavBackend->updateCalendarObject($id, $uri, $calendarData);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'calendar' => [
|
||||
'action' => 'update_card',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'carduri' => $uri,
|
||||
'card' => $calendarData
|
||||
]
|
||||
]);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -417,13 +532,23 @@ class Cdav extends Controller {
|
||||
|
||||
$id = explode(':', $_REQUEST['target']);
|
||||
|
||||
if(!cdav_perms($id[0],$calendars,true))
|
||||
if(! cdav_perms($id[0],$calendars,true))
|
||||
return;
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
|
||||
|
||||
$uri = $_REQUEST['uri'];
|
||||
|
||||
$caldavBackend->deleteCalendarObject($id, $uri);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'calendar' => [
|
||||
'action' => 'delete_card',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'carduri' => $uri
|
||||
]
|
||||
]);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -432,19 +557,21 @@ class Cdav extends Controller {
|
||||
|
||||
$id = [$_REQUEST['id'][0], $_REQUEST['id'][1]];
|
||||
|
||||
if(!cdav_perms($id[0],$calendars,true))
|
||||
if(! cdav_perms($id[0],$calendars,true))
|
||||
return;
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
$allday = $_REQUEST['allday'];
|
||||
|
||||
$uri = $_REQUEST['uri'];
|
||||
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
|
||||
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||
$dtstart = new \DateTime($start);
|
||||
if($_REQUEST['dtend']) {
|
||||
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
|
||||
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||
$dtend = new \DateTime($end);
|
||||
}
|
||||
|
||||
@@ -470,9 +597,17 @@ class Cdav extends Controller {
|
||||
unset($vcalendar->VEVENT->DTEND);
|
||||
|
||||
$calendarData = $vcalendar->serialize();
|
||||
|
||||
$caldavBackend->updateCalendarObject($id, $uri, $calendarData);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'calendar' => [
|
||||
'action' => 'update_card',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'carduri' => $uri,
|
||||
'card' => $calendarData
|
||||
]
|
||||
]);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -522,6 +657,14 @@ class Cdav extends Controller {
|
||||
$properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']];
|
||||
|
||||
$carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'addressbook' => [
|
||||
'action' => 'create',
|
||||
'uri' => $addressbookUri,
|
||||
'properties' => $properties
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
//edit addressbook
|
||||
@@ -532,21 +675,32 @@ class Cdav extends Controller {
|
||||
if(! cdav_perms($id,$addressbooks))
|
||||
return;
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
|
||||
|
||||
$mutations = [
|
||||
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname']
|
||||
];
|
||||
|
||||
$patch = new \Sabre\DAV\PropPatch($mutations);
|
||||
|
||||
$carddavBackend->updateAddressBook($id, $patch);
|
||||
|
||||
$patch->commit();
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'addressbook' => [
|
||||
'action' => 'edit',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'mutations' => $mutations,
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
//create addressbook card
|
||||
if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) {
|
||||
|
||||
$id = $_REQUEST['target'];
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
|
||||
|
||||
do {
|
||||
$duplicate = false;
|
||||
$uri = random_string(40) . '.vcf';
|
||||
@@ -568,86 +722,21 @@ class Cdav extends Controller {
|
||||
'N' => array_reverse(explode(' ', $fn))
|
||||
]);
|
||||
|
||||
$org = $_REQUEST['org'];
|
||||
if($org) {
|
||||
$vcard->ORG = $org;
|
||||
}
|
||||
$fields = $this->request_to_array($_REQUEST);
|
||||
|
||||
$title = $_REQUEST['title'];
|
||||
if($title) {
|
||||
$vcard->TITLE = $title;
|
||||
}
|
||||
|
||||
$tel = $_REQUEST['tel'];
|
||||
$tel_type = $_REQUEST['tel_type'];
|
||||
if($tel) {
|
||||
$i = 0;
|
||||
foreach($tel as $item) {
|
||||
if($item) {
|
||||
$vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$email = $_REQUEST['email'];
|
||||
$email_type = $_REQUEST['email_type'];
|
||||
if($email) {
|
||||
$i = 0;
|
||||
foreach($email as $item) {
|
||||
if($item) {
|
||||
$vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$impp = $_REQUEST['impp'];
|
||||
$impp_type = $_REQUEST['impp_type'];
|
||||
if($impp) {
|
||||
$i = 0;
|
||||
foreach($impp as $item) {
|
||||
if($item) {
|
||||
$vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$url = $_REQUEST['url'];
|
||||
$url_type = $_REQUEST['url_type'];
|
||||
if($url) {
|
||||
$i = 0;
|
||||
foreach($url as $item) {
|
||||
if($item) {
|
||||
$vcard->add('URL', $item, ['type' => $url_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$adr = $_REQUEST['adr'];
|
||||
$adr_type = $_REQUEST['adr_type'];
|
||||
|
||||
if($adr) {
|
||||
$i = 0;
|
||||
foreach($adr as $item) {
|
||||
if($item) {
|
||||
$vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$note = $_REQUEST['note'];
|
||||
if($note) {
|
||||
$vcard->NOTE = $note;
|
||||
}
|
||||
process_cdav_card($fields, $vcard);
|
||||
|
||||
$cardData = $vcard->serialize();
|
||||
|
||||
$carddavBackend->createCard($id, $uri, $cardData);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'addressbook' => [
|
||||
'action' => 'import',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'ids' => [ $uri ],
|
||||
'card' => $cardData
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
//edit addressbook card
|
||||
@@ -655,9 +744,11 @@ class Cdav extends Controller {
|
||||
|
||||
$id = $_REQUEST['target'];
|
||||
|
||||
if(!cdav_perms($id,$addressbooks))
|
||||
if(! cdav_perms($id,$addressbooks))
|
||||
return;
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
|
||||
|
||||
$uri = $_REQUEST['uri'];
|
||||
|
||||
$object = $carddavBackend->getCard($id, $uri);
|
||||
@@ -669,113 +760,23 @@ class Cdav extends Controller {
|
||||
$vcard->N = array_reverse(explode(' ', $fn));
|
||||
}
|
||||
|
||||
$org = $_REQUEST['org'];
|
||||
if($org) {
|
||||
$vcard->ORG = $org;
|
||||
}
|
||||
else {
|
||||
unset($vcard->ORG);
|
||||
}
|
||||
$fields = $this->request_to_array($_REQUEST);
|
||||
|
||||
$title = $_REQUEST['title'];
|
||||
if($title) {
|
||||
$vcard->TITLE = $title;
|
||||
}
|
||||
else {
|
||||
unset($vcard->TITLE);
|
||||
}
|
||||
|
||||
$tel = $_REQUEST['tel'];
|
||||
$tel_type = $_REQUEST['tel_type'];
|
||||
if($tel) {
|
||||
$i = 0;
|
||||
unset($vcard->TEL);
|
||||
foreach($tel as $item) {
|
||||
if($item) {
|
||||
$vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unset($vcard->TEL);
|
||||
}
|
||||
|
||||
$email = $_REQUEST['email'];
|
||||
$email_type = $_REQUEST['email_type'];
|
||||
if($email) {
|
||||
$i = 0;
|
||||
unset($vcard->EMAIL);
|
||||
foreach($email as $item) {
|
||||
if($item) {
|
||||
$vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unset($vcard->EMAIL);
|
||||
}
|
||||
|
||||
$impp = $_REQUEST['impp'];
|
||||
$impp_type = $_REQUEST['impp_type'];
|
||||
if($impp) {
|
||||
$i = 0;
|
||||
unset($vcard->IMPP);
|
||||
foreach($impp as $item) {
|
||||
if($item) {
|
||||
$vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unset($vcard->IMPP);
|
||||
}
|
||||
|
||||
$url = $_REQUEST['url'];
|
||||
$url_type = $_REQUEST['url_type'];
|
||||
if($url) {
|
||||
$i = 0;
|
||||
unset($vcard->URL);
|
||||
foreach($url as $item) {
|
||||
if($item) {
|
||||
$vcard->add('URL', $item, ['type' => $url_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unset($vcard->URL);
|
||||
}
|
||||
|
||||
$adr = $_REQUEST['adr'];
|
||||
$adr_type = $_REQUEST['adr_type'];
|
||||
if($adr) {
|
||||
$i = 0;
|
||||
unset($vcard->ADR);
|
||||
foreach($adr as $item) {
|
||||
if($item) {
|
||||
$vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unset($vcard->ADR);
|
||||
}
|
||||
|
||||
$note = $_REQUEST['note'];
|
||||
if($note) {
|
||||
$vcard->NOTE = $note;
|
||||
}
|
||||
else {
|
||||
unset($vcard->NOTE);
|
||||
}
|
||||
process_cdav_card($fields, $vcard, true);
|
||||
|
||||
$cardData = $vcard->serialize();
|
||||
|
||||
$carddavBackend->updateCard($id, $uri, $cardData);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'addressbook' => [
|
||||
'action' => 'update_card',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'carduri' => $uri,
|
||||
'card' => $cardData
|
||||
]
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
//delete addressbook card
|
||||
@@ -783,12 +784,22 @@ class Cdav extends Controller {
|
||||
|
||||
$id = $_REQUEST['target'];
|
||||
|
||||
if(!cdav_perms($id,$addressbooks))
|
||||
if(! cdav_perms($id,$addressbooks))
|
||||
return;
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
|
||||
|
||||
$uri = $_REQUEST['uri'];
|
||||
|
||||
$carddavBackend->deleteCard($id, $uri);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'addressbook' => [
|
||||
'action' => 'delete_card',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'carduri' => $uri
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,6 +810,8 @@ class Cdav extends Controller {
|
||||
|
||||
if($src) {
|
||||
|
||||
$carddata = @file_get_contents($src);
|
||||
|
||||
if($_REQUEST['c_upload']) {
|
||||
if($_REQUEST['target'] == 'channel_calendar') {
|
||||
$result = parse_ical_file($src,local_channel());
|
||||
@@ -815,72 +828,38 @@ class Cdav extends Controller {
|
||||
$ext = 'ics';
|
||||
$table = 'calendarobjects';
|
||||
$column = 'calendarid';
|
||||
$objects = new \Sabre\VObject\Splitter\ICalendar(@file_get_contents($src));
|
||||
$sync = 'calendar';
|
||||
$objects = new \Sabre\VObject\Splitter\ICalendar($carddata);
|
||||
$profile = \Sabre\VObject\Node::PROFILE_CALDAV;
|
||||
$backend = new \Sabre\CalDAV\Backend\PDO($pdo);
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id, 'calendarinstances');
|
||||
}
|
||||
|
||||
if($_REQUEST['a_upload']) {
|
||||
$id[] = intval($_REQUEST['target']);
|
||||
$id = intval($_REQUEST['target']);
|
||||
$ext = 'vcf';
|
||||
$table = 'cards';
|
||||
$column = 'addressbookid';
|
||||
$objects = new \Sabre\VObject\Splitter\VCard(@file_get_contents($src));
|
||||
$sync = 'addressbook';
|
||||
$objects = new \Sabre\VObject\Splitter\VCard($carddata);
|
||||
$profile = \Sabre\VObject\Node::PROFILE_CARDDAV;
|
||||
$backend = new \Sabre\CardDAV\Backend\PDO($pdo);
|
||||
|
||||
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
|
||||
}
|
||||
|
||||
while ($object = $objects->getNext()) {
|
||||
$ids = [];
|
||||
import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, $ids, true);
|
||||
|
||||
if($_REQUEST['a_upload']) {
|
||||
$object = $object->convert(\Sabre\VObject\Document::VCARD40);
|
||||
}
|
||||
|
||||
$ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR);
|
||||
|
||||
//level 3 Means that the document is invalid,
|
||||
//level 2 means a warning. A warning means it's valid but it could cause interopability issues,
|
||||
//level 1 means that there was a problem earlier, but the problem was automatically repaired.
|
||||
|
||||
if($ret[0]['level'] < 3) {
|
||||
do {
|
||||
$duplicate = false;
|
||||
$objectUri = random_string(40) . '.' . $ext;
|
||||
|
||||
$r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1",
|
||||
dbesc($id[0]),
|
||||
dbesc($objectUri)
|
||||
);
|
||||
|
||||
if (count($r))
|
||||
$duplicate = true;
|
||||
} while ($duplicate == true);
|
||||
|
||||
if($_REQUEST['c_upload']) {
|
||||
$backend->createCalendarObject($id, $objectUri, $object->serialize());
|
||||
}
|
||||
|
||||
if($_REQUEST['a_upload']) {
|
||||
$backend->createCard($id[0], $objectUri, $object->serialize());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($_REQUEST['c_upload']) {
|
||||
notice( '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL .
|
||||
'<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL .
|
||||
'<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL .
|
||||
'<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
|
||||
);
|
||||
}
|
||||
|
||||
if($_REQUEST['a_upload']) {
|
||||
notice( '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL .
|
||||
'<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL .
|
||||
'<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
$sync => [
|
||||
'action' => 'import',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'ids' => $ids,
|
||||
'card' => $carddata
|
||||
]
|
||||
]);
|
||||
}
|
||||
@unlink($src);
|
||||
}
|
||||
@@ -909,8 +888,6 @@ class Cdav extends Controller {
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
head_add_css('cdav.css');
|
||||
|
||||
if(!cdav_principal($principalUri)) {
|
||||
$this->activate($pdo, $channel);
|
||||
if(!cdav_principal($principalUri)) {
|
||||
@@ -1041,7 +1018,7 @@ class Cdav extends Controller {
|
||||
$catsenabled = feature_enabled(local_channel(), 'categories');
|
||||
|
||||
require_once('include/acl_selectors.php');
|
||||
|
||||
|
||||
$accesslist = new \Zotlabs\Access\AccessList($channel);
|
||||
$perm_defaults = $accesslist->get();
|
||||
|
||||
@@ -1082,6 +1059,7 @@ class Cdav extends Controller {
|
||||
'$cancel' => t('Cancel'),
|
||||
'$create' => t('Create'),
|
||||
'$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.'),
|
||||
'$disabled_warning' => t('Could not fetch calendar resource. The selected calendar might be disabled.'),
|
||||
|
||||
'$channel_hash' => $channel['channel_hash'],
|
||||
'$acl' => $acl,
|
||||
@@ -1191,7 +1169,18 @@ class Cdav extends Controller {
|
||||
if(! cdav_perms($id,$calendars))
|
||||
killme();
|
||||
|
||||
set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4));
|
||||
$cdavdata = $this->get_cdav_data($id, 'calendarinstances');
|
||||
|
||||
set_pconfig(local_channel(), 'cdav_calendar', $id, argv(4));
|
||||
|
||||
Libsync::build_sync_packet(local_channel(), [
|
||||
'calendar' => [
|
||||
'action' => 'switch',
|
||||
'uri' => $cdavdata['uri'],
|
||||
'switch' => intval(argv(4))
|
||||
]
|
||||
]);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -1202,7 +1191,18 @@ class Cdav extends Controller {
|
||||
if(! cdav_perms($id[0],$calendars))
|
||||
killme();
|
||||
|
||||
// get metadata before we delete it
|
||||
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
|
||||
|
||||
$caldavBackend->deleteCalendar($id);
|
||||
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'calendar' => [
|
||||
'action' => 'drop',
|
||||
'uri' => $cdavdata['uri']
|
||||
]
|
||||
]);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -1409,7 +1409,19 @@ class Cdav extends Controller {
|
||||
if(! cdav_perms($id,$addressbooks))
|
||||
return;
|
||||
|
||||
// get metadata before we delete it
|
||||
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
|
||||
|
||||
$carddavBackend->deleteAddressBook($id);
|
||||
|
||||
if($cdavdata)
|
||||
Libsync::build_sync_packet($channel['channel_id'], [
|
||||
'addressbook' => [
|
||||
'action' => 'drop',
|
||||
'uri' => $cdavdata['uri']
|
||||
]
|
||||
]);
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
@@ -1421,7 +1433,7 @@ class Cdav extends Controller {
|
||||
return;
|
||||
|
||||
$uri = 'principals/' . $channel['channel_address'];
|
||||
|
||||
|
||||
|
||||
$r = q("select * from principals where uri = '%s' limit 1",
|
||||
dbesc($uri)
|
||||
@@ -1461,4 +1473,36 @@ class Cdav extends Controller {
|
||||
}
|
||||
|
||||
|
||||
function get_cdav_data($id, $table) {
|
||||
|
||||
$r = q("SELECT * FROM $table WHERE id = %d LIMIT 1",
|
||||
intval($id)
|
||||
);
|
||||
|
||||
if(! $r)
|
||||
return false;
|
||||
|
||||
return $r[0];
|
||||
}
|
||||
|
||||
function request_to_array($req) {
|
||||
|
||||
$f = [];
|
||||
|
||||
$f['org'] = $req['org'];
|
||||
$f['title'] = $req['title'];
|
||||
$f['tel'] = $req['tel'];
|
||||
$f['tel_type'] = $req['tel_type'];
|
||||
$f['email'] = $req['email'];
|
||||
$f['email_type'] = $req['email_type'];
|
||||
$f['impp'] = $req['impp'];
|
||||
$f['impp_type'] = $req['impp_type'];
|
||||
$f['url'] = $req['url'];
|
||||
$f['url_type'] = $req['url_type'];
|
||||
$f['adr'] = $req['adr'];
|
||||
$f['adr_type'] = $req['adr_type'];
|
||||
$f['note'] = $req['note'];
|
||||
|
||||
return $f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,103 +4,149 @@ namespace Zotlabs\Module;
|
||||
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\PermissionDescription;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\Crypto;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\PermissionDescription;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
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');
|
||||
|
||||
|
||||
/**
|
||||
* @brief Channel Controller
|
||||
*
|
||||
*/
|
||||
|
||||
class Channel extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
if(in_array(substr($_GET['search'],0,1),[ '@', '!', '?']))
|
||||
goaway('search' . '?f=&search=' . $_GET['search']);
|
||||
if (array_key_exists('search', $_GET) && (in_array(substr($_GET['search'], 0, 1), ['@', '!', '?']) || strpos($_GET['search'], 'https://') === 0))
|
||||
goaway(z_root() . '/search?f=&search=' . $_GET['search']);
|
||||
|
||||
$which = null;
|
||||
if(argc() > 1)
|
||||
if (argc() > 1)
|
||||
$which = argv(1);
|
||||
if(! $which) {
|
||||
if(local_channel()) {
|
||||
if (!$which) {
|
||||
if (local_channel()) {
|
||||
$channel = App::get_channel();
|
||||
if($channel && $channel['channel_address'])
|
||||
$which = $channel['channel_address'];
|
||||
if ($channel && $channel['channel_address'])
|
||||
$which = $channel['channel_address'];
|
||||
}
|
||||
}
|
||||
if(! $which) {
|
||||
notice( t('You must be logged in to see this page.') . EOL );
|
||||
if (!$which) {
|
||||
notice(t('You must be logged in to see this page.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$profile = 0;
|
||||
$channel = App::get_channel();
|
||||
|
||||
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$which = $channel['channel_address'];
|
||||
if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$channel = App::get_channel();
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
}
|
||||
|
||||
$channel = channelx_by_nick($which);
|
||||
if(! $channel) {
|
||||
|
||||
// Do not use channelx_by_nick() here since it will dismiss deleted channels.
|
||||
// We need to provide zotinfo for deleted channels so that directories can pick up the info.
|
||||
$r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' LIMIT 1",
|
||||
dbesc($which)
|
||||
);
|
||||
|
||||
$channel = $r[0];
|
||||
|
||||
if (!$channel) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
// handle zot6 channel discovery
|
||||
// handle zot6 channel discovery
|
||||
|
||||
if(Libzot::is_zot_request()) {
|
||||
|
||||
$sigdata = HTTPSig::verify(file_get_contents('php://input'));
|
||||
if (Libzot::is_zot_request()) {
|
||||
|
||||
if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) {
|
||||
$data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'], 'target_url' => $sigdata['signer'] ]));
|
||||
$s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
$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']]));
|
||||
$s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($sigdata['signer'])
|
||||
);
|
||||
|
||||
if($s) {
|
||||
$data = json_encode(crypto_encapsulate($data,$s[0]['hubloc_sitekey'],Libzot::best_algorithm($s[0]['site_crypto'])));
|
||||
if ($s) {
|
||||
$data = json_encode(Crypto::encapsulate($data, $s[0]['hubloc_sitekey'], Libzot::best_algorithm($s[0]['site_crypto'])));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'] ]));
|
||||
$data = json_encode(Libzot::zotinfo(['guid_hash' => $channel['channel_hash']]));
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'Digest' => HTTPSig::generate_digest_header($data),
|
||||
'(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']
|
||||
];
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
|
||||
];
|
||||
|
||||
$h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $data;
|
||||
killme();
|
||||
}
|
||||
|
||||
if ($channel['channel_removed']) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$which = $channel['channel_address'];
|
||||
if (ActivityStreams::is_as_request($channel)) {
|
||||
|
||||
// Somebody may attempt an ActivityStreams fetch on one of our message permalinks
|
||||
// Make it do the right thing.
|
||||
|
||||
$mid = ((x($_REQUEST, 'mid')) ? $_REQUEST['mid'] : '');
|
||||
if ($mid && strpos($mid, 'b64.') === 0) {
|
||||
$decoded = @base64url_decode(substr($mid, 4));
|
||||
if ($decoded) {
|
||||
$mid = $decoded;
|
||||
}
|
||||
}
|
||||
if ($mid) {
|
||||
$obj = null;
|
||||
if (strpos($mid, z_root() . '/item/') === 0) {
|
||||
App::$argc = 2;
|
||||
App::$argv = ['item', basename($mid)];
|
||||
$obj = new Item();
|
||||
}
|
||||
if (strpos($mid, z_root() . '/activity/') === 0) {
|
||||
App::$argc = 2;
|
||||
App::$argv = ['activity', basename($mid)];
|
||||
$obj = new Activity();
|
||||
}
|
||||
if ($obj) {
|
||||
$obj->init();
|
||||
}
|
||||
}
|
||||
as_return_and_die(Activity::encode_person($channel, true), $channel);
|
||||
}
|
||||
|
||||
if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
}
|
||||
|
||||
head_add_link( [
|
||||
'rel' => 'alternate',
|
||||
head_add_link([
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/atom+xml',
|
||||
'title' => t('Posts and comments'),
|
||||
'href' => z_root() . '/feed/' . $which
|
||||
]);
|
||||
|
||||
head_add_link( [
|
||||
'rel' => 'alternate',
|
||||
head_add_link([
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/atom+xml',
|
||||
'title' => t('Only posts'),
|
||||
'href' => z_root() . '/feed/' . $which . '?f=&top=1'
|
||||
@@ -109,115 +155,121 @@ class Channel extends Controller {
|
||||
|
||||
// Run profile_load() here to make sure the theme is set before
|
||||
// we start loading content
|
||||
profile_load($which, $profile);
|
||||
|
||||
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((isset($r) && count($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'] : '');
|
||||
$mid = ((x($_REQUEST, 'mid')) ? $_REQUEST['mid'] : '');
|
||||
|
||||
if(strpos($mid,'b64.') === 0)
|
||||
$decoded = @base64url_decode(substr($mid,4));
|
||||
if($decoded)
|
||||
if (strpos($mid, 'b64.') === 0)
|
||||
$decoded = @base64url_decode(substr($mid, 4));
|
||||
if (isset($decoded))
|
||||
$mid = $decoded;
|
||||
|
||||
$datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : '');
|
||||
$datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : '');
|
||||
$datequery = ((x($_GET, 'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : '');
|
||||
$datequery2 = ((x($_GET, 'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : '');
|
||||
|
||||
if(observer_prohibited(true)) {
|
||||
if (observer_prohibited(true)) {
|
||||
return login();
|
||||
}
|
||||
|
||||
$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);
|
||||
$category = ((x($_REQUEST, 'cat')) ? $_REQUEST['cat'] : '');
|
||||
$hashtags = ((x($_REQUEST, 'tag')) ? $_REQUEST['tag'] : '');
|
||||
$order = ((x($_GET, 'order')) ? notags($_GET['order']) : 'post');
|
||||
$search = ((x($_GET, 'search')) ? $_GET['search'] : EMPTY_STR);
|
||||
|
||||
$groups = array();
|
||||
$groups = [];
|
||||
|
||||
$o = '';
|
||||
|
||||
if($update) {
|
||||
if ($update) {
|
||||
// Ensure we've got a profile owner if updating.
|
||||
App::$profile['profile_uid'] = App::$profile_uid = $update;
|
||||
}
|
||||
|
||||
$is_owner = (((local_channel()) && (App::$profile['profile_uid'] == local_channel())) ? true : false);
|
||||
|
||||
$channel = App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
$observer = App::get_observer();
|
||||
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
|
||||
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
|
||||
|
||||
$perms = get_all_perms(App::$profile['profile_uid'],$ob_hash);
|
||||
$perms = get_all_perms(App::$profile['profile_uid'], $ob_hash);
|
||||
|
||||
if(! $perms['view_stream']) {
|
||||
if (!$perms['view_stream']) {
|
||||
// We may want to make the target of this redirect configurable
|
||||
if($perms['view_profile']) {
|
||||
notice( t('Insufficient permissions. Request redirected to profile page.') . EOL);
|
||||
goaway (z_root() . "/profile/" . App::$profile['channel_address']);
|
||||
if ($perms['view_profile']) {
|
||||
notice(t('Insufficient permissions. Request redirected to profile page.') . EOL);
|
||||
goaway(z_root() . "/profile/" . App::$profile['channel_address']);
|
||||
}
|
||||
notice( t('Permission denied.') . EOL);
|
||||
notice(t('Permission denied.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(! $update) {
|
||||
if (!$update) {
|
||||
|
||||
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(
|
||||
'$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8')
|
||||
));
|
||||
if ($search) {
|
||||
$o .= replace_macros(get_markup_template("section_title.tpl"), [
|
||||
'$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT, 'UTF-8')
|
||||
]);
|
||||
}
|
||||
|
||||
if($channel && $is_owner) {
|
||||
$channel_acl = array(
|
||||
if ($channel && $is_owner) {
|
||||
$channel_acl = [
|
||||
'allow_cid' => $channel['channel_allow_cid'],
|
||||
'allow_gid' => $channel['channel_allow_gid'],
|
||||
'deny_cid' => $channel['channel_deny_cid'],
|
||||
'deny_gid' => $channel['channel_deny_gid']
|
||||
);
|
||||
'deny_cid' => $channel['channel_deny_cid'],
|
||||
'deny_gid' => $channel['channel_deny_gid']
|
||||
];
|
||||
}
|
||||
else {
|
||||
$channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
|
||||
$channel_acl = ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => ''];
|
||||
}
|
||||
|
||||
|
||||
if($perms['post_wall']) {
|
||||
if ($perms['post_wall']) {
|
||||
|
||||
$x = array(
|
||||
'is_owner' => $is_owner,
|
||||
'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(App::$profile['profile_uid'],'system','use_browser_location')))) ? true : false),
|
||||
'default_location' => (($is_owner) ? App::$profile['channel_location'] : ''),
|
||||
'nickname' => App::$profile['channel_address'],
|
||||
'lockstate' => (((strlen(App::$profile['channel_allow_cid'])) || (strlen(App::$profile['channel_allow_gid'])) || (strlen(App::$profile['channel_deny_cid'])) || (strlen(App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'),
|
||||
'acl' => (($is_owner) ? populate_acl($channel_acl,true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''),
|
||||
'permissions' => $channel_acl,
|
||||
'showacl' => (($is_owner) ? 'yes' : ''),
|
||||
'bang' => '',
|
||||
'visitor' => (($is_owner || $observer) ? true : false),
|
||||
'profile_uid' => App::$profile['profile_uid'],
|
||||
$x = [
|
||||
'is_owner' => $is_owner,
|
||||
'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(App::$profile['profile_uid'], 'system', 'use_browser_location')))) ? true : false),
|
||||
'default_location' => (($is_owner) ? App::$profile['channel_location'] : ''),
|
||||
'nickname' => App::$profile['channel_address'],
|
||||
'lockstate' => (((strlen(App::$profile['channel_allow_cid'])) || (strlen(App::$profile['channel_allow_gid'])) || (strlen(App::$profile['channel_deny_cid'])) || (strlen(App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'),
|
||||
'acl' => (($is_owner) ? populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''),
|
||||
'permissions' => $channel_acl,
|
||||
'showacl' => (($is_owner) ? 'yes' : ''),
|
||||
'bang' => '',
|
||||
'visitor' => (($is_owner || $observer) ? true : false),
|
||||
'profile_uid' => App::$profile['profile_uid'],
|
||||
'editor_autocomplete' => true,
|
||||
'bbco_autocomplete' => 'bbcode',
|
||||
'bbcode' => true,
|
||||
'jotnets' => true,
|
||||
'reset' => t('Reset form')
|
||||
);
|
||||
'bbco_autocomplete' => 'bbcode',
|
||||
'bbcode' => true,
|
||||
'jotnets' => true,
|
||||
'reset' => t('Reset form')
|
||||
];
|
||||
|
||||
$o .= status_editor($a,$x,false,'Channel');
|
||||
$o .= status_editor($a, $x, false, 'Channel');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -227,23 +279,29 @@ 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']);
|
||||
$sql_extra = item_permissions_sql(App::$profile['profile_uid']);
|
||||
|
||||
if(feature_enabled(App::$profile['profile_uid'], 'channel_list_mode') && (! $mid))
|
||||
if (feature_enabled(App::$profile['profile_uid'], 'channel_list_mode') && (!$mid))
|
||||
$page_mode = 'list';
|
||||
else
|
||||
$page_mode = 'client';
|
||||
|
||||
$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) {
|
||||
if ($search) {
|
||||
$search = escape_tags($search);
|
||||
if(strpos($search,'#') === 0) {
|
||||
$sql_extra .= term_query('item',substr($search,1),TERM_HASHTAG,TERM_COMMUNITYTAG);
|
||||
if (strpos($search, '#') === 0) {
|
||||
$sql_extra .= term_query('item', substr($search, 1), TERM_HASHTAG, TERM_COMMUNITYTAG);
|
||||
}
|
||||
else {
|
||||
$sql_extra .= sprintf(" AND (item.body like '%s' OR item.title like '%s') ",
|
||||
@@ -253,31 +311,21 @@ class Channel extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
head_add_link([
|
||||
head_add_link([
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/json+oembed',
|
||||
'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string),
|
||||
'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 (($update) && (!$load)) {
|
||||
|
||||
if($static && $simple_update)
|
||||
$simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
|
||||
|
||||
if(($update) && (! $load)) {
|
||||
|
||||
if($mid) {
|
||||
$r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal_update
|
||||
if ($mid) {
|
||||
$r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal_update
|
||||
AND item_wall = 1 $simple_update $sql_extra limit 1",
|
||||
dbesc($mid . '%'),
|
||||
dbesc($mid),
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
}
|
||||
else {
|
||||
$r = q("SELECT parent AS item_id from item
|
||||
@@ -289,69 +337,68 @@ class Channel extends Controller {
|
||||
ORDER BY created DESC",
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
if(x($category)) {
|
||||
$sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $category, TERM_CATEGORY));
|
||||
$sql_extra2 = '';
|
||||
if (x($category)) {
|
||||
$sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $category, TERM_CATEGORY));
|
||||
}
|
||||
if(x($hashtags)) {
|
||||
$sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
|
||||
if (x($hashtags)) {
|
||||
$sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
|
||||
}
|
||||
|
||||
if($datequery) {
|
||||
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery))));
|
||||
$order = 'post';
|
||||
if ($datequery) {
|
||||
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery))));
|
||||
$order = 'post';
|
||||
}
|
||||
if($datequery2) {
|
||||
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2))));
|
||||
if ($datequery2) {
|
||||
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery2))));
|
||||
}
|
||||
|
||||
if($order === 'post')
|
||||
if ($order === 'post')
|
||||
$ordering = "created";
|
||||
else
|
||||
$ordering = "commented";
|
||||
|
||||
|
||||
$itemspage = get_pconfig(local_channel(),'system','itemspage');
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
|
||||
$itemspage = get_pconfig(local_channel(), 'system', 'itemspage');
|
||||
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
|
||||
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
|
||||
|
||||
if($noscript_content || $load) {
|
||||
if($mid) {
|
||||
$r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal
|
||||
if ($noscript_content || $load) {
|
||||
if ($mid) {
|
||||
$r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal
|
||||
AND item_wall = 1 $sql_extra limit 1",
|
||||
dbesc($mid . '%'),
|
||||
dbesc($mid),
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
if (! $r) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
if (!$r) {
|
||||
notice(t('Permission denied.') . EOL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item
|
||||
$r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item
|
||||
left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids )
|
||||
WHERE true and item.uid = %d $item_normal
|
||||
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
|
||||
$sql_extra $sql_extra2
|
||||
ORDER BY $ordering DESC, item_id $pager_sql ",
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$r = array();
|
||||
$r = [];
|
||||
}
|
||||
}
|
||||
if($r) {
|
||||
if ($r) {
|
||||
|
||||
$parents_str = ids_to_querystr($r,'item_id');
|
||||
$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 )
|
||||
@@ -360,112 +407,89 @@ class Channel extends Controller {
|
||||
dbesc($parents_str)
|
||||
);
|
||||
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
$items = conv_sort($items,$ordering);
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
$items = conv_sort($items, $ordering);
|
||||
|
||||
if($load && $mid && (! count($items))) {
|
||||
if ($load && $mid && (!count($items))) {
|
||||
// This will happen if we don't have sufficient permissions
|
||||
// to view the parent item (or the item itself if it is toplevel)
|
||||
notice( t('Permission denied.') . EOL);
|
||||
notice(t('Permission denied.') . EOL);
|
||||
}
|
||||
|
||||
} else {
|
||||
$items = array();
|
||||
}
|
||||
else {
|
||||
$items = [];
|
||||
}
|
||||
|
||||
if((! $update) && (! $load)) {
|
||||
// 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'];
|
||||
}
|
||||
|
||||
if($decoded)
|
||||
$mode = (($search) ? 'search' : 'channel');
|
||||
|
||||
if ((!$update) && (!$load)) {
|
||||
|
||||
if (isset($decoded))
|
||||
$mid = 'b64.' . base64url_encode($mid);
|
||||
|
||||
// This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
|
||||
// because browser prefetching might change it on us. We have to deliver it with the page.
|
||||
|
||||
$maxheight = get_pconfig(App::$profile['profile_uid'],'system','channel_divmore_height');
|
||||
if(! $maxheight)
|
||||
$maxheight = get_pconfig(App::$profile['profile_uid'], 'system', 'channel_divmore_height');
|
||||
if (!$maxheight)
|
||||
$maxheight = 400;
|
||||
|
||||
$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";
|
||||
|
||||
App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
|
||||
'$baseurl' => z_root(),
|
||||
'$pgtype' => 'channel',
|
||||
'$uid' => ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : '0'),
|
||||
'$gid' => '0',
|
||||
'$cid' => '0',
|
||||
'$cmin' => '(-1)',
|
||||
'$cmax' => '(-1)',
|
||||
'$star' => '0',
|
||||
'$liked' => '0',
|
||||
'$conv' => '0',
|
||||
'$spam' => '0',
|
||||
'$nouveau' => '0',
|
||||
'$wall' => '1',
|
||||
'$fh' => '0',
|
||||
'$static' => $static,
|
||||
'$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1),
|
||||
'$search' => $search,
|
||||
'$xchan' => '',
|
||||
'$order' => (($order) ? urlencode($order) : ''),
|
||||
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
|
||||
'$file' => '',
|
||||
'$cats' => (($category) ? urlencode($category) : ''),
|
||||
'$tags' => (($hashtags) ? urlencode($hashtags) : ''),
|
||||
'$mid' => (($mid) ? urlencode($mid) : ''),
|
||||
'$verb' => '',
|
||||
'$net' => '',
|
||||
'$dend' => $datequery,
|
||||
'$dbegin' => $datequery2
|
||||
));
|
||||
. "; divmore_height = " . intval($maxheight) . ";</script>\r\n";
|
||||
|
||||
App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), [
|
||||
'$baseurl' => z_root(),
|
||||
'$pgtype' => 'channel',
|
||||
'$uid' => ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : '0'),
|
||||
'$gid' => '0',
|
||||
'$cid' => '0',
|
||||
'$cmin' => '(-1)',
|
||||
'$cmax' => '(-1)',
|
||||
'$star' => '0',
|
||||
'$liked' => '0',
|
||||
'$conv' => '0',
|
||||
'$spam' => '0',
|
||||
'$nouveau' => '0',
|
||||
'$wall' => '1',
|
||||
'$fh' => '0',
|
||||
'$dm' => '0',
|
||||
'$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1),
|
||||
'$search' => $search,
|
||||
'$xchan' => '',
|
||||
'$order' => (($order) ? urlencode($order) : ''),
|
||||
'$list' => ((x($_REQUEST, 'list')) ? intval($_REQUEST['list']) : 0),
|
||||
'$file' => '',
|
||||
'$cats' => (($category) ? urlencode($category) : ''),
|
||||
'$tags' => (($hashtags) ? urlencode($hashtags) : ''),
|
||||
'$mid' => (($mid) ? urlencode($mid) : ''),
|
||||
'$verb' => '',
|
||||
'$net' => '',
|
||||
'$dend' => $datequery,
|
||||
'$dbegin' => $datequery2,
|
||||
'$conv_mode' => 'channel',
|
||||
'$page_mode' => $page_mode
|
||||
]);
|
||||
}
|
||||
|
||||
$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())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$mode = (($search) ? 'search' : 'channel');
|
||||
|
||||
if($update) {
|
||||
$o .= conversation($items,$mode,$update,$page_mode);
|
||||
if ($update) {
|
||||
$o .= conversation($items, $mode, $update, $page_mode);
|
||||
}
|
||||
else {
|
||||
|
||||
$o .= '<noscript>';
|
||||
if($noscript_content) {
|
||||
$o .= conversation($items,$mode,$update,'traditional');
|
||||
if ($noscript_content) {
|
||||
$o .= conversation($items, $mode, $update, 'traditional');
|
||||
$o .= alt_pager(count($items));
|
||||
}
|
||||
else {
|
||||
@@ -473,16 +497,18 @@ class Channel extends Controller {
|
||||
}
|
||||
$o .= '</noscript>';
|
||||
|
||||
$o .= conversation($items,$mode,$update,$page_mode);
|
||||
$o .= conversation($items, $mode, $update, $page_mode);
|
||||
|
||||
if ($mid && $items[0]['title'])
|
||||
if ($mid && count($items) > 0 && isset($items[0]['title']))
|
||||
App::$page['title'] = $items[0]['title'] . " - " . App::$page['title'];
|
||||
|
||||
}
|
||||
|
||||
if($mid)
|
||||
if ($mid)
|
||||
$o .= '<div id="content-complete"></div>';
|
||||
|
||||
$_SESSION['loadtime'] = datetime_convert();
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Access\AccessList;
|
||||
use Zotlabs\Daemon\Master;
|
||||
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/datetime.php');
|
||||
@@ -8,34 +15,38 @@ require_once('include/event.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
class Channel_calendar extends \Zotlabs\Web\Controller {
|
||||
class Channel_calendar extends Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
|
||||
|
||||
if(! local_channel())
|
||||
|
||||
logger('post: ' . print_r($_REQUEST, true), LOGGER_DATA);
|
||||
|
||||
$uid = local_channel();
|
||||
|
||||
if (!$uid)
|
||||
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();
|
||||
|
||||
$event_id = ((x($_POST, 'event_id')) ? intval($_POST['event_id']) : 0);
|
||||
|
||||
$xchan = ((x($_POST, 'xchan')) ? dbesc($_POST['xchan']) : '');
|
||||
|
||||
// only allow editing your own events.
|
||||
if(($xchan) && ($xchan !== get_observer_hash()))
|
||||
if (($xchan) && ($xchan !== get_observer_hash()))
|
||||
return;
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
$categories = escape_tags(trim($_POST['categories']));
|
||||
|
||||
|
||||
// allday events have adjust = 0, normal events have adjust = 1
|
||||
$adjust = intval($_POST['adjust']);
|
||||
|
||||
$start = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtstart'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart'])));
|
||||
$finish = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtend'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend'])));
|
||||
$timezone = ((x($_POST, 'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
$start = datetime_convert((($adjust) ? $tz : 'UTC'), 'UTC', escape_tags($_REQUEST['dtstart']));
|
||||
$finish = datetime_convert((($adjust) ? $tz : 'UTC'), 'UTC', escape_tags($_REQUEST['dtend']));
|
||||
|
||||
if (!$adjust)
|
||||
$tz = 'UTC';
|
||||
|
||||
$summary = escape_tags(trim($_POST['summary']));
|
||||
$desc = escape_tags(trim($_POST['desc']));
|
||||
@@ -46,88 +57,86 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
||||
// 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.'));
|
||||
|
||||
if (strcmp($finish, $start) < 0) {
|
||||
notice(t('Event can not end before it has started.') . 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) {
|
||||
if ((!$summary) || (!$start)) {
|
||||
notice(t('Event title and start time are required.') . EOL);
|
||||
if (intval($_REQUEST['preview'])) {
|
||||
echo(t('Unable to generate preview.'));
|
||||
}
|
||||
killme();
|
||||
}
|
||||
|
||||
$acl = new AccessList([]);
|
||||
|
||||
if ($event_id) {
|
||||
$x = q("select * from event where id = %d and uid = %d limit 1",
|
||||
intval($event_id),
|
||||
intval(local_channel())
|
||||
intval($uid)
|
||||
);
|
||||
if(! $x) {
|
||||
notice( t('Event not found.') . EOL);
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
echo( t('Unable to generate preview.'));
|
||||
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();
|
||||
$edited = datetime_convert();
|
||||
}
|
||||
else {
|
||||
$created = $edited = datetime_convert();
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
|
||||
|
||||
$post_tags = array();
|
||||
$channel = \App::get_channel();
|
||||
$ac = $acl->get();
|
||||
$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'];
|
||||
$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());
|
||||
$results = linkify_tags($desc, $uid);
|
||||
|
||||
if($results) {
|
||||
if ($results) {
|
||||
// Set permissions based on tag replacements
|
||||
set_linkified_perms($results, $str_contact_allow, $str_group_allow, local_channel(), false, $private);
|
||||
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $uid, $private);
|
||||
|
||||
foreach($results as $result) {
|
||||
foreach ($results as $result) {
|
||||
$success = $result['success'];
|
||||
if($success['replaced']) {
|
||||
if ($success['replaced']) {
|
||||
$post_tags[] = array(
|
||||
'uid' => local_channel(),
|
||||
'uid' => $uid,
|
||||
'ttype' => $success['termtype'],
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'term' => $success['term'],
|
||||
'url' => $success['url']
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(strlen($categories)) {
|
||||
$cats = explode(',',$categories);
|
||||
foreach($cats as $cat) {
|
||||
if (strlen($categories)) {
|
||||
$cats = explode(',', $categories);
|
||||
foreach ($cats as $cat) {
|
||||
$post_tags[] = array(
|
||||
'uid' => local_channel(),
|
||||
'uid' => $uid,
|
||||
'ttype' => TERM_CATEGORY,
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'term' => trim($cat),
|
||||
@@ -135,175 +144,170 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$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'])) {
|
||||
$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'] = $uid;
|
||||
$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)
|
||||
|
||||
if ($post_tags)
|
||||
$datarray['term'] = $post_tags;
|
||||
|
||||
$item_id = event_store_item($datarray,$event);
|
||||
|
||||
if($item_id) {
|
||||
|
||||
$item_id = event_store_item($datarray, $event);
|
||||
|
||||
if ($item_id) {
|
||||
$r = q("select * from item where id = %d",
|
||||
intval($item_id)
|
||||
);
|
||||
if($r) {
|
||||
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",
|
||||
$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) {
|
||||
build_sync_packet($channel['channel_id'],array('event_item' => array(encode_item($sync_item[0],true)),'event' => $z));
|
||||
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));
|
||||
|
||||
Master::Summon(array('Notifier', 'event', $item_id));
|
||||
|
||||
killme();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
if(argc() > 2 && argv(1) == 'ical') {
|
||||
|
||||
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) {
|
||||
if ($r) {
|
||||
header('Content-type: text/calendar');
|
||||
header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"' );
|
||||
header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"');
|
||||
echo ical_wrapper($r);
|
||||
killme();
|
||||
}
|
||||
else {
|
||||
notice( t('Event not found.') . EOL );
|
||||
notice(t('Event not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(! local_channel()) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
|
||||
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",
|
||||
if ((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
|
||||
q("update event set dismissed = 1 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() > 2) && (argv(1) === 'unignore') && intval(argv(2))) {
|
||||
q("update event set dismissed = 0 where id = %d and uid = %d",
|
||||
intval(argv(2)),
|
||||
intval(local_channel())
|
||||
);
|
||||
}
|
||||
|
||||
if(argc() > 1) {
|
||||
if(argc() > 2 && argv(1) === 'add') {
|
||||
$mode = 'add';
|
||||
$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';
|
||||
if (argc() > 2 && argv(1) === 'drop') {
|
||||
$mode = 'drop';
|
||||
$event_id = argv(2);
|
||||
}
|
||||
if(argc() <= 2 && argv(1) === 'export') {
|
||||
if (argc() <= 2 && argv(1) === 'export') {
|
||||
$export = true;
|
||||
}
|
||||
if(argc() > 2 && intval(argv(1)) && intval(argv(2))) {
|
||||
if (argc() > 2 && intval(argv(1)) && intval(argv(2))) {
|
||||
$mode = 'view';
|
||||
}
|
||||
if(argc() <= 2) {
|
||||
$mode = 'view';
|
||||
if (argc() <= 2) {
|
||||
$mode = 'view';
|
||||
$event_id = argv(1);
|
||||
}
|
||||
}
|
||||
|
||||
if($mode === 'add') {
|
||||
event_addtocal($item_id,local_channel());
|
||||
|
||||
if ($mode === 'add') {
|
||||
event_addtocal($item_id, local_channel());
|
||||
killme();
|
||||
}
|
||||
|
||||
if($mode == 'view') {
|
||||
|
||||
|
||||
if ($mode == 'view') {
|
||||
|
||||
/* edit/create form */
|
||||
if($event_id) {
|
||||
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||
if ($event_id) {
|
||||
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'];
|
||||
$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);
|
||||
|
||||
$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
|
||||
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) {
|
||||
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",
|
||||
@@ -329,104 +333,105 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
||||
dbesc($adjust_finish)
|
||||
);
|
||||
}
|
||||
|
||||
if($r && ! $export) {
|
||||
|
||||
if ($r && !$export) {
|
||||
xchan_query($r);
|
||||
$r = fetch_post_tags($r,true);
|
||||
$r = fetch_post_tags($r, true);
|
||||
$r = sort_by_date($r);
|
||||
}
|
||||
|
||||
$events = [];
|
||||
|
||||
if($r) {
|
||||
|
||||
foreach($r as $rr) {
|
||||
|
||||
$tz = get_iconfig($rr, 'event', 'timezone');
|
||||
if ($r) {
|
||||
|
||||
if(! $tz)
|
||||
$tz = 'UTC';
|
||||
foreach ($r as $rr) {
|
||||
|
||||
$start = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
|
||||
if ($rr['nofinish']){
|
||||
$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($tz, date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
|
||||
}
|
||||
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']) {
|
||||
$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))
|
||||
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'),'','');
|
||||
|
||||
$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' => htmlentities($rr['summary'], ENT_COMPAT, 'UTF-8', false),
|
||||
'editable' => $edit ? true : false,
|
||||
'item' => $rr,
|
||||
'plink' => [$rr['plink'], t('Link to source')],
|
||||
'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8', false),
|
||||
'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8', false),
|
||||
'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
|
||||
'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) {
|
||||
|
||||
if ($export) {
|
||||
header('Content-type: text/calendar');
|
||||
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );
|
||||
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"');
|
||||
echo ical_wrapper($r);
|
||||
killme();
|
||||
}
|
||||
|
||||
if (\App::$argv[1] === 'json'){
|
||||
|
||||
if (App::$argv[1] === 'json') {
|
||||
json_return_and_die($events);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($mode === 'drop' && $event_id) {
|
||||
|
||||
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) {
|
||||
|
||||
if ($r) {
|
||||
$r = q("delete from event where event_hash = '%s' and uid = %d",
|
||||
dbesc($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if($r) {
|
||||
if ($r) {
|
||||
|
||||
$sync_event['event_deleted'] = 1;
|
||||
build_sync_packet(0,array('event' => array($sync_event)));
|
||||
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),
|
||||
@@ -435,11 +440,11 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
||||
|
||||
if ($i) {
|
||||
|
||||
$can_delete = false;
|
||||
$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'])) {
|
||||
if ($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) {
|
||||
$can_delete = true;
|
||||
}
|
||||
|
||||
@@ -447,49 +452,49 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
||||
// If the item originated on this site+channel the deletion will propagate downstream.
|
||||
// Otherwise just the local copy is removed.
|
||||
|
||||
if(is_site_admin()) {
|
||||
if (is_site_admin()) {
|
||||
$local_delete = true;
|
||||
if(intval($i[0]['item_origin']))
|
||||
if (intval($i[0]['item_origin']))
|
||||
$can_delete = true;
|
||||
}
|
||||
|
||||
if($can_delete || $local_delete) {
|
||||
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;
|
||||
$complex = false;
|
||||
|
||||
if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) {
|
||||
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);
|
||||
drop_item($i[0]['id'], true, DROPITEM_PHASE1);
|
||||
$complex = true;
|
||||
}
|
||||
|
||||
$ii = q("select * from item where id = %d",
|
||||
intval($i[0]['id'])
|
||||
);
|
||||
if($ii) {
|
||||
if ($ii) {
|
||||
xchan_query($ii);
|
||||
$sync_item = fetch_post_tags($ii);
|
||||
build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
|
||||
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']);
|
||||
if ($complex) {
|
||||
tag_deliver($i[0]['uid'], $i[0]['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
killme();
|
||||
}
|
||||
notice( t('Failed to remove event' ) . EOL);
|
||||
notice(t('Failed to remove event') . EOL);
|
||||
killme();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user