mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 09:01:15 -04:00
Compare commits
3021 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2805520d1b | ||
|
|
fb7ca18820 | ||
|
|
1b00d5657f | ||
|
|
cd9f35e78a | ||
|
|
f9cedab964 | ||
|
|
9ec516e5a4 | ||
|
|
550b6d90a4 | ||
|
|
5cb92b6e21 | ||
|
|
8a7b221412 | ||
|
|
d092e79ebc | ||
|
|
2ddb88a34d | ||
|
|
71761c9039 | ||
|
|
16555b93bb | ||
|
|
bd5e834b42 | ||
|
|
2eb4f093be | ||
|
|
d4bf587103 | ||
|
|
ae7bd8b644 | ||
|
|
f89cede020 | ||
|
|
59facf6f00 | ||
|
|
01d93733ae | ||
|
|
4c434129a6 | ||
|
|
b40499b4c1 | ||
|
|
66333aedb7 | ||
|
|
47071c58aa | ||
|
|
79d99688b4 | ||
|
|
edcb0631aa | ||
|
|
bc361e6469 | ||
|
|
c95ef1a5c0 | ||
|
|
0c0891f64f | ||
|
|
23828f53bc | ||
|
|
f909e129ab | ||
|
|
7d4bcc2e8b | ||
|
|
2eb4d87621 | ||
|
|
435888c1a3 | ||
|
|
e69fabcd71 | ||
|
|
1a283301cf | ||
|
|
031df70cf8 | ||
|
|
3ad36db7dd | ||
|
|
e16ea1ae05 | ||
|
|
941135a0a6 | ||
|
|
29776ecea2 | ||
|
|
d2edef5c5a | ||
|
|
da9349ea62 | ||
|
|
de0d2afc15 | ||
|
|
d8c94c2003 | ||
|
|
0e71bfe222 | ||
|
|
0ae402e624 | ||
|
|
b96dc11ddd | ||
|
|
37b539eaa5 | ||
|
|
0741708086 | ||
|
|
a30cfd8fec | ||
|
|
633cd11c5b | ||
|
|
3101c6540a | ||
|
|
d2d6be73b8 | ||
|
|
a46e2c1e6d | ||
|
|
2b0404fefc | ||
|
|
7ef9462286 | ||
|
|
c6e7a7eaee | ||
|
|
999e142370 | ||
|
|
a7ad117a83 | ||
|
|
1ba44fc117 | ||
|
|
ca5610ebf1 | ||
|
|
e5c70a1304 | ||
|
|
7dd2308534 | ||
|
|
62eee07b6e | ||
|
|
f6d9406063 | ||
|
|
34125177e8 | ||
|
|
d977b5d662 | ||
|
|
e36677b757 | ||
|
|
4d54755057 | ||
|
|
91917c98e4 | ||
|
|
2f687de477 | ||
|
|
5446062b95 | ||
|
|
c9e170dfcc | ||
|
|
e3a19469eb | ||
|
|
45f8e43be4 | ||
|
|
7ef0b05ce6 | ||
|
|
c5a0ec4e93 | ||
|
|
1c17768dc5 | ||
|
|
86e1dd4673 | ||
|
|
0ee41c3341 | ||
|
|
e1c2835173 | ||
|
|
5c6d3753ef | ||
|
|
6e881bcef2 | ||
|
|
4f9a933108 | ||
|
|
9f8585914c | ||
|
|
3ba27b9752 | ||
|
|
abae5de4d8 | ||
|
|
6952c5a3f5 | ||
|
|
0184d2c292 | ||
|
|
7a40561aaa | ||
|
|
79e6c9590a | ||
|
|
12a963cc40 | ||
|
|
f89975fd0e | ||
|
|
b4dffe5946 | ||
|
|
539b69d507 | ||
|
|
9927363f39 | ||
|
|
1a4f59cd70 | ||
|
|
25727a24a5 | ||
|
|
2fd2dc964b | ||
|
|
935b032f15 | ||
|
|
2bb58843ab | ||
|
|
00512579f3 | ||
|
|
6f09796142 | ||
|
|
697a74f37e | ||
|
|
d16b6c3838 | ||
|
|
e4461f2e61 | ||
|
|
baf1b8b02d | ||
|
|
3ce1373ae0 | ||
|
|
4002531b92 | ||
|
|
004d0f074d | ||
|
|
e87887c328 | ||
|
|
2de2c8e207 | ||
|
|
c76f19f19a | ||
|
|
a050e8c8f5 | ||
|
|
ae1fad5de7 | ||
|
|
68ca8951a8 | ||
|
|
1e4718eae1 | ||
|
|
680cf25f37 | ||
|
|
7ec6df495f | ||
|
|
aeda31fda7 | ||
|
|
5248aa3065 | ||
|
|
67767c5853 | ||
|
|
6de1aec683 | ||
|
|
221d3cdf6a | ||
|
|
1ff12c5520 | ||
|
|
41376ec2cd | ||
|
|
bf335ecaf3 | ||
|
|
424bc73f58 | ||
|
|
59e6989cbc | ||
|
|
0e6b27c9f4 | ||
|
|
0e157e4e8b | ||
|
|
805074a0f9 | ||
|
|
5216c5b232 | ||
|
|
8633162f0c | ||
|
|
c392a77b46 | ||
|
|
08c2c9bc22 | ||
|
|
f64bd590a8 | ||
|
|
131ffcf582 | ||
|
|
b17a0aef17 | ||
|
|
8a21783fa5 | ||
|
|
53152e2ef5 | ||
|
|
ca6ba92d82 | ||
|
|
04516b787a | ||
|
|
6e124a4d72 | ||
|
|
6da65c7ddc | ||
|
|
9eb332f032 | ||
|
|
30ddee65a4 | ||
|
|
63dc8d7fc4 | ||
|
|
a1a287bac7 | ||
|
|
e9b786d5e8 | ||
|
|
ad9fb411f6 | ||
|
|
1ff982983e | ||
|
|
8c6c43d762 | ||
|
|
6baf197842 | ||
|
|
42e5a50e4f | ||
|
|
b713c9a491 | ||
|
|
64ade742d9 | ||
|
|
1870c3c876 | ||
|
|
23b272aafd | ||
|
|
057db41758 | ||
|
|
839c5a8e41 | ||
|
|
36b8b6bf6c | ||
|
|
40d74fa779 | ||
|
|
249bdeb642 | ||
|
|
b4ee80d1ea | ||
|
|
96bf9d0769 | ||
|
|
7fc9c83986 | ||
|
|
5502f1cc63 | ||
|
|
b55801323c | ||
|
|
818374c8cc | ||
|
|
e80191d4cd | ||
|
|
c2a796b6ea | ||
|
|
00694f0dfd | ||
|
|
134f4c5b52 | ||
|
|
0840fc42f9 | ||
|
|
2650a647e9 | ||
|
|
3311269162 | ||
|
|
b2172d39f6 | ||
|
|
f4d39bd3c8 | ||
|
|
1cf659033b | ||
|
|
3dc5527690 | ||
|
|
81b02d04b5 | ||
|
|
95f6f9e10a | ||
|
|
9554f53519 | ||
|
|
5d7081a224 | ||
|
|
9cbdf3f31f | ||
|
|
c8bc1b560b | ||
|
|
40ae6b396f | ||
|
|
9c117ffa05 | ||
|
|
9e95f189ed | ||
|
|
221b31bcc6 | ||
|
|
8879776d64 | ||
|
|
5edd13c6bb | ||
|
|
7ca289edd0 | ||
|
|
bf434818d7 | ||
|
|
03aeb88832 | ||
|
|
bb5b33a0d3 | ||
|
|
53931017b9 | ||
|
|
e9ca17cec1 | ||
|
|
f70956964b | ||
|
|
4547a9d9d3 | ||
|
|
71accb6b0a | ||
|
|
2a95500b65 | ||
|
|
2ddad66ce7 | ||
|
|
108be24aed | ||
|
|
71efb05658 | ||
|
|
a9a36894cb | ||
|
|
bc9778e02f | ||
|
|
a83d2efe84 | ||
|
|
d3856caf81 | ||
|
|
e1f9b1c47d | ||
|
|
497c953d0e | ||
|
|
bec76bd057 | ||
|
|
54f4762e1a | ||
|
|
8bf5c18425 | ||
|
|
c36bb17475 | ||
|
|
2291fcdf11 | ||
|
|
4070c46d15 | ||
|
|
a749db8d0f | ||
|
|
10ba98c4f5 | ||
|
|
108a3efe0b | ||
|
|
ccd826f63a | ||
|
|
5e5f0aa955 | ||
|
|
f9a4c53e3f | ||
|
|
60b576568e | ||
|
|
d0e1b73205 | ||
|
|
ef2448e17e | ||
|
|
99a5cf1ad4 | ||
|
|
bc3113ae16 | ||
|
|
fb475da008 | ||
|
|
d5fc3ad646 | ||
|
|
8b7da6e318 | ||
|
|
ed208c4bcc | ||
|
|
6ab65519a0 | ||
|
|
4549bc89ec | ||
|
|
a0430f91bd | ||
|
|
624bb1db8d | ||
|
|
9f522bbe6c | ||
|
|
931da3b4f7 | ||
|
|
5a25fd54a4 | ||
|
|
9f0f4c50a4 | ||
|
|
0bf3d31578 | ||
|
|
8ca293c3e4 | ||
|
|
ba0c877ffc | ||
|
|
b8e00c2dc9 | ||
|
|
2dd48898a8 | ||
|
|
66fc807655 | ||
|
|
653eb2909b | ||
|
|
72520a2dd9 | ||
|
|
a7d4666a70 | ||
|
|
13476d5003 | ||
|
|
879cdedec3 | ||
|
|
05bd2a1f9e | ||
|
|
c49d1547c4 | ||
|
|
ad35363c2e | ||
|
|
b3f70140e5 | ||
|
|
2f21dc50b4 | ||
|
|
cbd8c2483b | ||
|
|
03475bfb15 | ||
|
|
bb9411e7dc | ||
|
|
bce4e2d022 | ||
|
|
7cfc14fef7 | ||
|
|
f220cf3173 | ||
|
|
725359b1aa | ||
|
|
937d6cb1ef | ||
|
|
118a5edebc | ||
|
|
1b4333e8d9 | ||
|
|
d66a0b50e9 | ||
|
|
1d56b9a1bb | ||
|
|
96535ee4df | ||
|
|
b55f314d7e | ||
|
|
480862d714 | ||
|
|
990a3af2a7 | ||
|
|
1f5a23143a | ||
|
|
fcfb9e9758 | ||
|
|
9beee689ce | ||
|
|
2c388c3833 | ||
|
|
1a75066616 | ||
|
|
3dfb0bcae9 | ||
|
|
9ac0b77e92 | ||
|
|
6421a32520 | ||
|
|
fdcae52740 | ||
|
|
a8752844ef | ||
|
|
e04ce5028e | ||
|
|
f2c4d80ac0 | ||
|
|
d8a6226805 | ||
|
|
fedf60a32c | ||
|
|
b3548fefc1 | ||
|
|
febd64c527 | ||
|
|
d67a5c5070 | ||
|
|
aefe7ddd8f | ||
|
|
254dea7558 | ||
|
|
b1550f7922 | ||
|
|
2d07c3e45d | ||
|
|
e5f3406cb5 | ||
|
|
185ddf1eaf | ||
|
|
2734335869 | ||
|
|
0132c4e36e | ||
|
|
7dee47183d | ||
|
|
9c4988c297 | ||
|
|
3bfbc70587 | ||
|
|
34858fce1c | ||
|
|
b47dab0ee9 | ||
|
|
6eeb033b96 | ||
|
|
0679cb8e00 | ||
|
|
3abc9ee387 | ||
|
|
2e9211cf41 | ||
|
|
40377796ed | ||
|
|
fedad7f31a | ||
|
|
d2a34e0107 | ||
|
|
769c822568 | ||
|
|
c452a621fe | ||
|
|
231ab95ef6 | ||
|
|
7c01b59ffb | ||
|
|
e79668ddf4 | ||
|
|
dc6b6fc353 | ||
|
|
34ea58cf38 | ||
|
|
199168c318 | ||
|
|
063d4bbd7d | ||
|
|
29fd9b9d64 | ||
|
|
c301baafb5 | ||
|
|
4282672201 | ||
|
|
ae705dd865 | ||
|
|
f0fa2ce171 | ||
|
|
d6a9a9927c | ||
|
|
40b4636858 | ||
|
|
97fe499b63 | ||
|
|
e0915cffda | ||
|
|
7602de85c3 | ||
|
|
0787817eb8 | ||
|
|
e030648957 | ||
|
|
b815935fd7 | ||
|
|
a5000ba311 | ||
|
|
5e2bb874c8 | ||
|
|
fcb5a7f645 | ||
|
|
b8c6520abb | ||
|
|
1d99c3d3f7 | ||
|
|
5e112b395d | ||
|
|
d1a8e7813a | ||
|
|
a0582fec12 | ||
|
|
2cd3a7b3f0 | ||
|
|
47448b11cd | ||
|
|
e63f043841 | ||
|
|
33dd0c83e3 | ||
|
|
32dad136f8 | ||
|
|
073ed52538 | ||
|
|
eef828cf3e | ||
|
|
d0b5930a3a | ||
|
|
c66ad9ccc8 | ||
|
|
9959a15c8e | ||
|
|
f0e4b4dc84 | ||
|
|
f62f808368 | ||
|
|
530a521679 | ||
|
|
50782dfb83 | ||
|
|
27a142d5c5 | ||
|
|
6d00b2e63d | ||
|
|
7be1415a3a | ||
|
|
0a30b12f7d | ||
|
|
3058cbfbb2 | ||
|
|
ae780c977b | ||
|
|
e146a67f4b | ||
|
|
162d86983a | ||
|
|
8534366a31 | ||
|
|
d1c6617dc9 | ||
|
|
6f994709b9 | ||
|
|
55d833a9c8 | ||
|
|
8ba4745097 | ||
|
|
940a0c8b10 | ||
|
|
8928b24e23 | ||
|
|
ae9a9191f3 | ||
|
|
cb553bd016 | ||
|
|
a75c61d71e | ||
|
|
c1dc16a89d | ||
|
|
66436ce4a2 | ||
|
|
62b1ff4ba1 | ||
|
|
304d136437 | ||
|
|
1b4268b9b0 | ||
|
|
a7968e6525 | ||
|
|
e59cc3d404 | ||
|
|
3a2d126877 | ||
|
|
ee3d6fcfee | ||
|
|
09d929bd56 | ||
|
|
bd55ae15f2 | ||
|
|
2ca80118bf | ||
|
|
04eb20ac35 | ||
|
|
f299391aa1 | ||
|
|
c334fc9d22 | ||
|
|
8520088376 | ||
|
|
9ada8518dc | ||
|
|
f0c09b374c | ||
|
|
c5f33baf27 | ||
|
|
2efcdd92e0 | ||
|
|
38fda98b6d | ||
|
|
f9fd195c24 | ||
|
|
01e82090b2 | ||
|
|
39602ede37 | ||
|
|
98a311ae40 | ||
|
|
5c398b3e8f | ||
|
|
83e585ee9b | ||
|
|
e386499bfa | ||
|
|
4552630bf8 | ||
|
|
2d8065a780 | ||
|
|
b94da93c74 | ||
|
|
695045f197 | ||
|
|
376733bd08 | ||
|
|
4c7c5137c5 | ||
|
|
930b9820f2 | ||
|
|
b2fa63f2c8 | ||
|
|
1390e1db39 | ||
|
|
e7768ae954 | ||
|
|
38d977e546 | ||
|
|
3e38a24f0a | ||
|
|
0784cd593a | ||
|
|
9c5d2ee563 | ||
|
|
be5f7c2e67 | ||
|
|
0d0f73fb67 | ||
|
|
680be6cfec | ||
|
|
2ab3d072b0 | ||
|
|
943ecff623 | ||
|
|
03973f5d1d | ||
|
|
c42a0fa9b6 | ||
|
|
61522ed31d | ||
|
|
29a527426a | ||
|
|
62ac0ff21e | ||
|
|
a41c7caa18 | ||
|
|
b3ca31bce7 | ||
|
|
b02f6a1dae | ||
|
|
d35609f33a | ||
|
|
8c19ab8f9f | ||
|
|
30ae198b89 | ||
|
|
bddeab3ac1 | ||
|
|
591349ee74 | ||
|
|
9081a25e64 | ||
|
|
1beadfc6e7 | ||
|
|
f4af532c5a | ||
|
|
76eb1a9d78 | ||
|
|
14a2790dcb | ||
|
|
46f54db197 | ||
|
|
4ffd7587a9 | ||
|
|
c48c62c7a8 | ||
|
|
9e7fd20ade | ||
|
|
efa1d381ba | ||
|
|
740fa058aa | ||
|
|
37f56e1efd | ||
|
|
6294be371a | ||
|
|
bee7549a1e | ||
|
|
db14dbacc9 | ||
|
|
27058e6297 | ||
|
|
b41175e0e2 | ||
|
|
eeea3251ad | ||
|
|
34ffff3947 | ||
|
|
65ed3818ec | ||
|
|
c8417df6f1 | ||
|
|
dc3be7ecf7 | ||
|
|
cf3c0b593b | ||
|
|
34f64148e8 | ||
|
|
fc5dad1983 | ||
|
|
c3c40548b9 | ||
|
|
0e2e932102 | ||
|
|
6930c4e23b | ||
|
|
01b9f2dfcf | ||
|
|
0cc6f66a26 | ||
|
|
d384f55dd1 | ||
|
|
1893368aa5 | ||
|
|
a520063265 | ||
|
|
1e171a72a0 | ||
|
|
5b1a0d93b9 | ||
|
|
7e04662a9c | ||
|
|
a804549781 | ||
|
|
2a60f1cc6e | ||
|
|
2ddff785e5 | ||
|
|
38882efb5c | ||
|
|
6f7786b068 | ||
|
|
0819141f03 | ||
|
|
329ef5049f | ||
|
|
34bb8c65d6 | ||
|
|
575ccae6f9 | ||
|
|
486be87e33 | ||
|
|
c0350861ef | ||
|
|
a7ec1805e3 | ||
|
|
4b06bc552f | ||
|
|
76ee7b7eea | ||
|
|
04b1e7e34f | ||
|
|
17dbb156e1 | ||
|
|
135117c637 | ||
|
|
d3348f7855 | ||
|
|
39bbcb66c8 | ||
|
|
d45e8e4d20 | ||
|
|
d65052c1ac | ||
|
|
2fbc42753f | ||
|
|
4195865965 | ||
|
|
de3f6fbeba | ||
|
|
6a377120bd | ||
|
|
502226b0a6 | ||
|
|
78206b48f4 | ||
|
|
dc3cec06ca | ||
|
|
5a7688e099 | ||
|
|
c721f01c76 | ||
|
|
463806822c | ||
|
|
b74c2f001d | ||
|
|
9fc7a8b626 | ||
|
|
3ffd92a6c3 | ||
|
|
29b02e5329 | ||
|
|
97584e046f | ||
|
|
09d2fce85d | ||
|
|
fc3060cb29 | ||
|
|
9804a67165 | ||
|
|
21eddefa41 | ||
|
|
9b62e7eedb | ||
|
|
bf30cfd8a4 | ||
|
|
139ffae367 | ||
|
|
51a48cc264 | ||
|
|
abbca12565 | ||
|
|
9e9d96a2ec | ||
|
|
615c9f1cbe | ||
|
|
7d75d0cfbd | ||
|
|
5468de2c6a | ||
|
|
6d8aabab23 | ||
|
|
e74359fcfe | ||
|
|
53c842c614 | ||
|
|
23ececeb34 | ||
|
|
521c9eb566 | ||
|
|
35877b1382 | ||
|
|
c531287170 | ||
|
|
8e79a81b88 | ||
|
|
b95ceb301f | ||
|
|
76a94495c4 | ||
|
|
b6b2299b4e | ||
|
|
34ddea87d3 | ||
|
|
3d318542cb | ||
|
|
4a8c3cdc61 | ||
|
|
c0b6f2d95f | ||
|
|
9ca7fccab8 | ||
|
|
d91fcfc866 | ||
|
|
29b53f3b9d | ||
|
|
30987095c7 | ||
|
|
43b93de570 | ||
|
|
5b310cf315 | ||
|
|
a1c2a57ea6 | ||
|
|
34bf8f1133 | ||
|
|
c708ec577e | ||
|
|
c185685f2d | ||
|
|
daee5b3477 | ||
|
|
5d0346ee30 | ||
|
|
85ad5355cf | ||
|
|
4c8b84633a | ||
|
|
c0dd4d748d | ||
|
|
c94f25570b | ||
|
|
ffa5e08832 | ||
|
|
63243c8e04 | ||
|
|
21c4ec2de0 | ||
|
|
a8d87af418 | ||
|
|
7b084a065e | ||
|
|
47f6b202e5 | ||
|
|
f588d8379b | ||
|
|
58827e130b | ||
|
|
d702334604 | ||
|
|
b04aa799e3 | ||
|
|
e113f6cb9d | ||
|
|
bc13b7eb72 | ||
|
|
f50b395da6 | ||
|
|
a0e8e40f1c | ||
|
|
cb6055c1b8 | ||
|
|
25424c16e4 | ||
|
|
99dcdee67a | ||
|
|
99928f1aea | ||
|
|
1740ae2104 | ||
|
|
d8372f8433 | ||
|
|
2a15d2c421 | ||
|
|
bacf19688f | ||
|
|
31fbdcf6c5 | ||
|
|
c8818cb7b3 | ||
|
|
eb20789821 | ||
|
|
c90862217e | ||
|
|
df87d6feeb | ||
|
|
6c808abcfc | ||
|
|
f1822bdfab | ||
|
|
c3428acd80 | ||
|
|
d619192b22 | ||
|
|
5bdc713afe | ||
|
|
46eff1c937 | ||
|
|
76e1ea1c02 | ||
|
|
755076a8e5 | ||
|
|
b49f7b8b34 | ||
|
|
c4dd8885e4 | ||
|
|
4c82952b58 | ||
|
|
0da69cb9c7 | ||
|
|
36e244060c | ||
|
|
b13a9f57af | ||
|
|
0aa67ad7f9 | ||
|
|
195a3a6827 | ||
|
|
38ecff1220 | ||
|
|
67e64287af | ||
|
|
b022703b0b | ||
|
|
e8069c0d93 | ||
|
|
7a1c6b64c2 | ||
|
|
8250cb1e8d | ||
|
|
ffe2c4d42b | ||
|
|
f06c970628 | ||
|
|
99bce46b32 | ||
|
|
f711913778 | ||
|
|
a8ac231667 | ||
|
|
f7c8791a6d | ||
|
|
7acc775c91 | ||
|
|
c2e21e837f | ||
|
|
755d0f54f7 | ||
|
|
f62d66ff25 | ||
|
|
406d19f930 | ||
|
|
42b13614eb | ||
|
|
c942bd67fe | ||
|
|
b8dc3d74b6 | ||
|
|
38fb263737 | ||
|
|
b55beed2f9 | ||
|
|
e9278c03c1 | ||
|
|
ae1fe83784 | ||
|
|
717a547c40 | ||
|
|
ec491e87ab | ||
|
|
42e30d0835 | ||
|
|
5b19418e48 | ||
|
|
1bc9a7373f | ||
|
|
23e59b5dcc | ||
|
|
c6b459cf96 | ||
|
|
33254b4cac | ||
|
|
44da40d18d | ||
|
|
c742f25801 | ||
|
|
b153687bf1 | ||
|
|
3318f093da | ||
|
|
d98d56c3b5 | ||
|
|
c3f5f6c7ad | ||
|
|
5f21edcc53 | ||
|
|
cd0731cbb0 | ||
|
|
f392ddec2f | ||
|
|
df71168ab7 | ||
|
|
e93b26bf54 | ||
|
|
a73d4a8cbd | ||
|
|
20ee57801c | ||
|
|
6a270d7f02 | ||
|
|
68639637c9 | ||
|
|
0d1eabbc33 | ||
|
|
dce249f7a9 | ||
|
|
1723d4fbd8 | ||
|
|
c4b09f1a4f | ||
|
|
788c973c13 | ||
|
|
465c5c8cfb | ||
|
|
ee28ba5be1 | ||
|
|
9a22e9cf39 | ||
|
|
2513f605b6 | ||
|
|
3b1ffb2028 | ||
|
|
47c6624e12 | ||
|
|
b6f1b064d3 | ||
|
|
17d89467df | ||
|
|
1282214d48 | ||
|
|
f4bc6ee615 | ||
|
|
f8b8d8c540 | ||
|
|
57ff667438 | ||
|
|
abe3039926 | ||
|
|
82a1117e91 | ||
|
|
b6ff3a4d99 | ||
|
|
f4046efcb2 | ||
|
|
fc1d3831cf | ||
|
|
867deda247 | ||
|
|
f8149face5 | ||
|
|
7e2aecd8bb | ||
|
|
105d121199 | ||
|
|
37d662f2f5 | ||
|
|
5b50454b4d | ||
|
|
b5e4c08fc5 | ||
|
|
db39cd8b7c | ||
|
|
a35f741a35 | ||
|
|
fc02e018cb | ||
|
|
b14a530efb | ||
|
|
f70bc571bd | ||
|
|
8cc64176b4 | ||
|
|
7450ac1a31 | ||
|
|
c72e5e3b66 | ||
|
|
5e811819e2 | ||
|
|
f1c0034a18 | ||
|
|
7342cb81a3 | ||
|
|
b40e858556 | ||
|
|
95a4ed7d6a | ||
|
|
2c2d4b6b95 | ||
|
|
4490eae4fe | ||
|
|
9d59cb0135 | ||
|
|
7d348fe69f | ||
|
|
fa8fb9e73f | ||
|
|
f6093872ec | ||
|
|
e8030e29d9 | ||
|
|
df8bb0596a | ||
|
|
0003e0b8a5 | ||
|
|
e42703d557 | ||
|
|
4636e56395 | ||
|
|
27ebeffad4 | ||
|
|
07110cee17 | ||
|
|
afa1f1416b | ||
|
|
f8dfcab0ca | ||
|
|
e14fd920d6 | ||
|
|
8c10fdae5b | ||
|
|
eee027d9ff | ||
|
|
1b1fb5d26a | ||
|
|
c36e0805d8 | ||
|
|
5c56041185 | ||
|
|
5aefe0b74f | ||
|
|
20e0359efd | ||
|
|
9c790e5a90 | ||
|
|
9c79b5be77 | ||
|
|
2d9a4f4e42 | ||
|
|
565602538c | ||
|
|
78972725ae | ||
|
|
5ab90f7791 | ||
|
|
b90d98fc2b | ||
|
|
eca3ae393b | ||
|
|
2bd69495d2 | ||
|
|
bfd3da43ac | ||
|
|
32a9eaf3b6 | ||
|
|
91cea1f28a | ||
|
|
220ed35f58 | ||
|
|
b1cf5d4e44 | ||
|
|
fe330ec1bb | ||
|
|
2968bf8241 | ||
|
|
a40babbf0d | ||
|
|
7822257e1c | ||
|
|
b37165c62b | ||
|
|
5e9d267959 | ||
|
|
1a1e6b6810 | ||
|
|
88140002e7 | ||
|
|
efc203d958 | ||
|
|
42d4cdcc39 | ||
|
|
fd433b3eb6 | ||
|
|
7483adb8ad | ||
|
|
45fd462f80 | ||
|
|
807003adf7 | ||
|
|
1b0a17c7db | ||
|
|
60b145833c | ||
|
|
39458b2ba8 | ||
|
|
5de38b3632 | ||
|
|
6ced3426cf | ||
|
|
43460c9d19 | ||
|
|
ca17fb01bc | ||
|
|
a6f65aa9c5 | ||
|
|
ae9a7727d6 | ||
|
|
3ac5d5257b | ||
|
|
668d7c73ed | ||
|
|
c95f708c91 | ||
|
|
06e214e567 | ||
|
|
18f8cafee0 | ||
|
|
6bd6afac05 | ||
|
|
fe7ecede70 | ||
|
|
089708ab9f | ||
|
|
daa844c038 | ||
|
|
4049992228 | ||
|
|
7c576c91b7 | ||
|
|
17bd364614 | ||
|
|
25ffd39519 | ||
|
|
acfa527e3e | ||
|
|
b512416cb3 | ||
|
|
bd116c53a1 | ||
|
|
1251fca256 | ||
|
|
b2fe21709c | ||
|
|
c082d12b59 | ||
|
|
9a4ca44255 | ||
|
|
6fce9a41b0 | ||
|
|
65acdd7b15 | ||
|
|
a209374cbd | ||
|
|
c1bb87db98 | ||
|
|
8bae40449f | ||
|
|
bc3bb4694a | ||
|
|
22588e58f3 | ||
|
|
69ba4eb055 | ||
|
|
687b9fb6a2 | ||
|
|
9b9ca9695c | ||
|
|
6357c69868 | ||
|
|
15cb7ab7a1 | ||
|
|
2c741bd24d | ||
|
|
3f72a3beb6 | ||
|
|
42de18d96d | ||
|
|
4bdbdab399 | ||
|
|
c7515b8687 | ||
|
|
c79e39a488 | ||
|
|
d639104b71 | ||
|
|
c66a5ba732 | ||
|
|
79f9b49dd7 | ||
|
|
8b542c250a | ||
|
|
55237683d2 | ||
|
|
27401794e1 | ||
|
|
862a7c2dba | ||
|
|
bb31a4620e | ||
|
|
7aaade8b23 | ||
|
|
a622f533ad | ||
|
|
0dd27dabd6 | ||
|
|
8ab464acf2 | ||
|
|
db18438db2 | ||
|
|
f885f98611 | ||
|
|
9b8b85545f | ||
|
|
532b479f96 | ||
|
|
422dfca6d7 | ||
|
|
c3d1474f59 | ||
|
|
99873504e4 | ||
|
|
138a67298d | ||
|
|
aca1551e86 | ||
|
|
ca32850a32 | ||
|
|
ba6f069997 | ||
|
|
c6c6b52ccd | ||
|
|
96c334e730 | ||
|
|
3e503ec3a3 | ||
|
|
e455fae334 | ||
|
|
29f3dc2fa3 | ||
|
|
aa41b16757 | ||
|
|
f4d59abe41 | ||
|
|
18de58fd8b | ||
|
|
4c2b188f8b | ||
|
|
08f65420f4 | ||
|
|
b90228b319 | ||
|
|
ad2c165f26 | ||
|
|
af5218593a | ||
|
|
f19acd9f50 | ||
|
|
59940e7f05 | ||
|
|
094536e633 | ||
|
|
4f2a439873 | ||
|
|
63bdab2b5f | ||
|
|
14733f8482 | ||
|
|
b830bbd084 | ||
|
|
c1894c5a39 | ||
|
|
e91e488e1f | ||
|
|
e6dac085cb | ||
|
|
5023a5b56b | ||
|
|
32d37d1178 | ||
|
|
848221649e | ||
|
|
f5f357060b | ||
|
|
98eea41865 | ||
|
|
8ac529f5ae | ||
|
|
b5fed08dd4 | ||
|
|
9bfcaf2669 | ||
|
|
af05ee7e1c | ||
|
|
3918439020 | ||
|
|
3b71e115a4 | ||
|
|
c33660a015 | ||
|
|
7963d4cb8f | ||
|
|
16281e0e7f | ||
|
|
72c58e60d7 | ||
|
|
4b48ff2868 | ||
|
|
8e212d30d0 | ||
|
|
b9ae396e74 | ||
|
|
3a38946f8a | ||
|
|
d0d3a5454e | ||
|
|
04c6d77d2c | ||
|
|
c2c5730d00 | ||
|
|
21a6dffd5f | ||
|
|
7430989212 | ||
|
|
2e26a13f81 | ||
|
|
404ebd4d5e | ||
|
|
11ea7bf0fc | ||
|
|
6da7fe7d27 | ||
|
|
538e540531 | ||
|
|
53138f4b09 | ||
|
|
3d71367f30 | ||
|
|
bb52ff9b4b | ||
|
|
ab5b82221c | ||
|
|
5c3b89a68b | ||
|
|
da923d7749 | ||
|
|
55d905fdd9 | ||
|
|
4ba70a3fae | ||
|
|
a5835b0e85 | ||
|
|
ed4e5c9bcf | ||
|
|
d8793de629 | ||
|
|
f45cb38cd3 | ||
|
|
0722188ea6 | ||
|
|
d6f81e139a | ||
|
|
58ee147653 | ||
|
|
28ad6a6883 | ||
|
|
9de8aefa98 | ||
|
|
66c273ae8d | ||
|
|
b27fbf209e | ||
|
|
4afd1ac705 | ||
|
|
d556ef59e6 | ||
|
|
81e972b85c | ||
|
|
3bb04cc323 | ||
|
|
9ff43f081f | ||
|
|
8c014e3b6b | ||
|
|
d8378a17c9 | ||
|
|
574a01727e | ||
|
|
b5cea3301d | ||
|
|
9346a06f35 | ||
|
|
250e917c6e | ||
|
|
7b1cd37cd6 | ||
|
|
47e83a15c1 | ||
|
|
597e847a3b | ||
|
|
47f3b41d5e | ||
|
|
e7f4c1ffd1 | ||
|
|
9a87b8bf1b | ||
|
|
dac27aab68 | ||
|
|
069a5429c9 | ||
|
|
b1eaa810ce | ||
|
|
e5e3c268a2 | ||
|
|
22dff49673 | ||
|
|
591905c282 | ||
|
|
6ed160e4fa | ||
|
|
d462230b82 | ||
|
|
e48ed9d06d | ||
|
|
6236869ebe | ||
|
|
2c7c9ae2d7 | ||
|
|
b9b4e71f7d | ||
|
|
b0bf646d71 | ||
|
|
5cb5ecdb54 | ||
|
|
44fa5ac9a1 | ||
|
|
9a19f7eac9 | ||
|
|
af0896bb8b | ||
|
|
817237ef77 | ||
|
|
fbefff6eed | ||
|
|
4ba47698d7 | ||
|
|
2688abf25a | ||
|
|
5eb79bd51e | ||
|
|
d3f5f778a4 | ||
|
|
3eeb2b0ee4 | ||
|
|
230a1919dd | ||
|
|
14004fbf7f | ||
|
|
73e8af98f2 | ||
|
|
0117a0019b | ||
|
|
35ff8781f0 | ||
|
|
2d17442f28 | ||
|
|
5c179522bb | ||
|
|
b35d95da52 | ||
|
|
feca5afaa5 | ||
|
|
9cb5274d30 | ||
|
|
2870fd46da | ||
|
|
dff8ef91a6 | ||
|
|
0588975e37 | ||
|
|
e0600b241a | ||
|
|
d19aa8fb3b | ||
|
|
989a4f3d49 | ||
|
|
2a2c4d3e9c | ||
|
|
a451449766 | ||
|
|
3347fab105 | ||
|
|
33a6c92629 | ||
|
|
0707d33493 | ||
|
|
89e4006b2d | ||
|
|
4eb8921635 | ||
|
|
26ac452c96 | ||
|
|
7122e1522a | ||
|
|
5497adfde6 | ||
|
|
d4c2e50285 | ||
|
|
7ba58208f2 | ||
|
|
cc83677711 | ||
|
|
c28cce1b54 | ||
|
|
9052695a13 | ||
|
|
46b8db53ab | ||
|
|
0b716b3cc7 | ||
|
|
d115e09abc | ||
|
|
0f803aa3ae | ||
|
|
e5dc3c05df | ||
|
|
1cfe5c3e16 | ||
|
|
e2d0269b5c | ||
|
|
b95c61d2c2 | ||
|
|
7b0f8f2896 | ||
|
|
25a81ea500 | ||
|
|
4c5f0a05c7 | ||
|
|
977a55eb84 | ||
|
|
8ec001c87b | ||
|
|
ddbc55d166 | ||
|
|
9a3a0d94ea | ||
|
|
1d3a59e0cd | ||
|
|
ad7c84eda7 | ||
|
|
fe62b245ca | ||
|
|
6084360588 | ||
|
|
52995bde12 | ||
|
|
0f54b26e9d | ||
|
|
2523ebc76a | ||
|
|
c1ce211b56 | ||
|
|
1aa7826331 | ||
|
|
29a1556541 | ||
|
|
93f48aa805 | ||
|
|
95367a8267 | ||
|
|
97ef781a0f | ||
|
|
81351d2952 | ||
|
|
8d28649e1b | ||
|
|
9495fef79b | ||
|
|
de02d4c04b | ||
|
|
18cd3926d7 | ||
|
|
0e1e1cda7a | ||
|
|
b3f2374b57 | ||
|
|
793881b9f9 | ||
|
|
529824d010 | ||
|
|
c47e21f3a7 | ||
|
|
d83c013bec | ||
|
|
17220b2465 | ||
|
|
5dcf053b4c | ||
|
|
a11fe8c6c6 | ||
|
|
70370407ad | ||
|
|
7973f11cd7 | ||
|
|
44371c9adf | ||
|
|
3d40ea7f44 | ||
|
|
8a3446c021 | ||
|
|
6a8cc313da | ||
|
|
7a1c72d5a4 | ||
|
|
4e7525c355 | ||
|
|
e20a2752d6 | ||
|
|
e25558e24d | ||
|
|
ada7d4eef5 | ||
|
|
3fb4077672 | ||
|
|
5b73cee0d8 | ||
|
|
8343f63964 | ||
|
|
5532560d07 | ||
|
|
ed277dbda9 | ||
|
|
2866c0b173 | ||
|
|
5eaabbdb18 | ||
|
|
d24fbb51fc | ||
|
|
6e4c9d684d | ||
|
|
3ff184f8bb | ||
|
|
a68b5f9de4 | ||
|
|
d5bf42faf0 | ||
|
|
88b13658a7 | ||
|
|
05152ac8c8 | ||
|
|
aa2106f949 | ||
|
|
6261d0826c | ||
|
|
2e7a915ee8 | ||
|
|
0081bafab2 | ||
|
|
64b59b4358 | ||
|
|
19f9bbcad4 | ||
|
|
f399528055 | ||
|
|
fea3980c01 | ||
|
|
8804499cb7 | ||
|
|
fa1878fda1 | ||
|
|
b129d74a38 | ||
|
|
189da4fdc1 | ||
|
|
824894baf0 | ||
|
|
2bd4f7384e | ||
|
|
1c44b37cb0 | ||
|
|
ab0da7db13 | ||
|
|
052633d570 | ||
|
|
3bb71a6ba8 | ||
|
|
7093b66b76 | ||
|
|
168010a32c | ||
|
|
6eb84a3d9a | ||
|
|
69d909596a | ||
|
|
dd296e1aaa | ||
|
|
c3bbc35e84 | ||
|
|
952407363e | ||
|
|
2deb75de8d | ||
|
|
a2403042c2 | ||
|
|
87cf2039ad | ||
|
|
db4109c2a0 | ||
|
|
36564b5aa7 | ||
|
|
101fc33c63 | ||
|
|
bd2270deb6 | ||
|
|
5b72f6f09d | ||
|
|
ee1cec8de2 | ||
|
|
b0a499d8b1 | ||
|
|
08f70c49f8 | ||
|
|
cddc021772 | ||
|
|
571bae9d1c | ||
|
|
e01666526e | ||
|
|
562a160a52 | ||
|
|
cb57c4ea18 | ||
|
|
b7ffec6fbe | ||
|
|
94be9f115b | ||
|
|
693736df7c | ||
|
|
943e7dd242 | ||
|
|
c1526b473b | ||
|
|
d459dfac74 | ||
|
|
cec2f0d894 | ||
|
|
9722d157bf | ||
|
|
6bcd24ab90 | ||
|
|
c6133d2558 | ||
|
|
ea8d38dec0 | ||
|
|
0fa41f082d | ||
|
|
83b1f62e13 | ||
|
|
b19213b60b | ||
|
|
3c5b18913f | ||
|
|
676a65cd61 | ||
|
|
95fb66b433 | ||
|
|
a57529bc54 | ||
|
|
4f15c08805 | ||
|
|
7b2f4b0814 | ||
|
|
3051e2c268 | ||
|
|
d7489e3913 | ||
|
|
62606bf006 | ||
|
|
c68f2bc2d1 | ||
|
|
f5669c9935 | ||
|
|
9e2bdb012e | ||
|
|
d8ac25c35a | ||
|
|
2dd47a9f59 | ||
|
|
a92ad512bb | ||
|
|
e39b29cc4b | ||
|
|
76ed9f3915 | ||
|
|
73b53675b1 | ||
|
|
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 | ||
|
|
efda8aac1d | ||
|
|
a84cec4acd | ||
|
|
cf6b7a4236 | ||
|
|
998f46b45c | ||
|
|
5ca352a6c3 | ||
|
|
a34bd3b013 | ||
|
|
c268bc327a | ||
|
|
e79a27c654 | ||
|
|
2f0bac8ddf | ||
|
|
12d7d1c3f0 | ||
|
|
34ca2cddd4 | ||
|
|
fa076efd3b | ||
|
|
b55676d089 | ||
|
|
9b71c090c5 | ||
|
|
0f8e4e4eed | ||
|
|
de1e3d7b17 | ||
|
|
3d077a0bc6 | ||
|
|
c74d1f4bf7 | ||
|
|
776e1211bc | ||
|
|
b5a8ca6ef7 | ||
|
|
2c198ed89a | ||
|
|
17fdeb9e1f | ||
|
|
e41858f57c | ||
|
|
219d47f04c | ||
|
|
750721c1a0 | ||
|
|
b66b43256b | ||
|
|
58cacaff06 | ||
|
|
9aebb01d62 | ||
|
|
f3b4308cb5 | ||
|
|
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 | ||
|
|
686530c187 | ||
|
|
e5c8273f72 | ||
|
|
440f7bacd6 | ||
|
|
ba22d3e9b6 | ||
|
|
33463152e8 | ||
|
|
657af3024e | ||
|
|
7d82a34538 | ||
|
|
a0b788e96a | ||
|
|
50c14d353b | ||
|
|
b63aa3079b | ||
|
|
25be24e6b8 | ||
|
|
2ec2da5dff | ||
|
|
b3df15a3c6 | ||
|
|
481ecee9e8 | ||
|
|
462980c70a | ||
|
|
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 | ||
|
|
a96345401f | ||
|
|
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 | ||
|
|
9359fc065c | ||
|
|
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 | ||
|
|
878be8fff0 | ||
|
|
beb418b093 | ||
|
|
a033c439f3 | ||
|
|
66e4bc327f | ||
|
|
df362e4f81 | ||
|
|
0f89d2b8e0 | ||
|
|
82ee980172 | ||
|
|
463a8d338e | ||
|
|
d074bb65da | ||
|
|
b7c411470b | ||
|
|
e09e6c5524 | ||
|
|
fa73c8d15e | ||
|
|
6060ca127b | ||
|
|
ca4e0351cf | ||
|
|
f3be2ecc9d | ||
|
|
135305d975 | ||
|
|
34aa8ba3cc | ||
|
|
28fe91dfa7 | ||
|
|
883b519714 | ||
|
|
9dae590c64 | ||
|
|
fc88c306ab | ||
|
|
d4159e8333 | ||
|
|
90d04082a1 | ||
|
|
a84c7271f2 | ||
|
|
f46ddf2273 | ||
|
|
b401869d30 | ||
|
|
cc55716879 | ||
|
|
ddad4f604b | ||
|
|
dc553ab309 | ||
|
|
a2d170385b | ||
|
|
a275726988 | ||
|
|
863d4d83a1 | ||
|
|
5664f5e0a2 | ||
|
|
d50381c9c6 | ||
|
|
c9bbe1a735 | ||
|
|
18b9d1efd8 | ||
|
|
85f1845d15 | ||
|
|
c34fc416a2 | ||
|
|
7794ee5a88 | ||
|
|
65068479b9 | ||
|
|
655ae9d1cd | ||
|
|
76163fc37b | ||
|
|
92f3c5ae21 | ||
|
|
136bc13ff6 | ||
|
|
62b738da95 | ||
|
|
e7c7f91a3f | ||
|
|
8a65fc8a43 | ||
|
|
c3ec5d4d6a | ||
|
|
0aeb4d6fb5 | ||
|
|
edd4ac791f | ||
|
|
27577824de | ||
|
|
0b95e061a3 | ||
|
|
383917eb0f | ||
|
|
7e3046b85c | ||
|
|
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 | ||
|
|
85cf25a2a8 | ||
|
|
19bb9e0181 | ||
|
|
9545a81166 | ||
|
|
1712eceaf9 | ||
|
|
6f93d9848c | ||
|
|
bde429cff6 | ||
|
|
4c8d33d1eb | ||
|
|
fac7826efa | ||
|
|
3e133bbfa3 | ||
|
|
6c8d1bdffe | ||
|
|
59fc495593 | ||
|
|
60827bdcc4 | ||
|
|
f992feb71c | ||
|
|
cf66e66db8 | ||
|
|
63aa3948e5 | ||
|
|
7899ed6f69 | ||
|
|
5e44239657 | ||
|
|
17cd452fff | ||
|
|
004861fbb7 | ||
|
|
8727f12b18 | ||
|
|
05604e4bd2 | ||
|
|
fd7d497cd1 | ||
|
|
a974d0d52d | ||
|
|
c850a61a89 | ||
|
|
3a2fdec241 | ||
|
|
08b804cd2d | ||
|
|
cc9f41df5f | ||
|
|
bb3784d8dd | ||
|
|
c997360b4a | ||
|
|
88fa18204f | ||
|
|
e8f3b7f853 | ||
|
|
e28341ca4b | ||
|
|
6c11a020ee | ||
|
|
732ca49b02 | ||
|
|
06ac3e896a | ||
|
|
f5062c0507 | ||
|
|
7a7f57fa45 | ||
|
|
0e0024218f | ||
|
|
6c12880f5b | ||
|
|
eb472111a8 | ||
|
|
681dc70205 | ||
|
|
130cfbf231 | ||
|
|
3070baf04e | ||
|
|
72629ca511 | ||
|
|
892e9cd835 | ||
|
|
109c66aea3 | ||
|
|
1a76e83fa4 | ||
|
|
2fa788b01b | ||
|
|
028cbdcffa | ||
|
|
8aefbd911b | ||
|
|
f046a34d34 | ||
|
|
9e3a4402e0 | ||
|
|
df228237de | ||
|
|
958217dd55 | ||
|
|
2f80fdae97 | ||
|
|
c5703306ef | ||
|
|
8848885d9a | ||
|
|
c1cab6789e | ||
|
|
7889612edc | ||
|
|
eacc29ded0 | ||
|
|
ea04c93bfd | ||
|
|
8692977585 | ||
|
|
6a40f3ed60 | ||
|
|
dd1f631d9d | ||
|
|
9f403a4d6b | ||
|
|
a3f726baa8 | ||
|
|
e4ca3609d9 | ||
|
|
bc092d8d78 | ||
|
|
dd5933b048 | ||
|
|
24cb04c346 | ||
|
|
e64a7b87a8 | ||
|
|
5b4aa1afc2 | ||
|
|
89205276ab | ||
|
|
e6da910ee2 | ||
|
|
b6bd2884d5 | ||
|
|
097b2390db | ||
|
|
23a0dbe3cc | ||
|
|
545ece82b3 | ||
|
|
eaea947b74 | ||
|
|
385be35ed5 | ||
|
|
dd374eaebf | ||
|
|
8715f74d29 | ||
|
|
152224944b | ||
|
|
f86d12c8f4 | ||
|
|
e130b58b20 | ||
|
|
a921deafd1 | ||
|
|
071fba2f71 | ||
|
|
9de729e3e7 | ||
|
|
7cf5bd30f2 | ||
|
|
e6cee2965a | ||
|
|
b07c55a0d9 | ||
|
|
823c0434eb | ||
|
|
22162635e7 | ||
|
|
29c5e74d31 | ||
|
|
c439fe0437 | ||
|
|
b21db670b4 | ||
|
|
1f84aa9809 | ||
|
|
4ac249c26c | ||
|
|
85a29fce94 | ||
|
|
fc726bfb4b | ||
|
|
f6a4084f81 | ||
|
|
d5f89c165a | ||
|
|
dce5080e53 | ||
|
|
2221d4d612 | ||
|
|
5f73a46c05 | ||
|
|
b782c6bd16 | ||
|
|
ab8d8aa552 | ||
|
|
f955276694 | ||
|
|
77cc60faf2 | ||
|
|
dcd8a05809 | ||
|
|
62e466f774 | ||
|
|
70777a047d | ||
|
|
a93bd8d944 | ||
|
|
28c3259449 | ||
|
|
0d0ede7b14 | ||
|
|
33ac85f637 | ||
|
|
efd9421dc9 | ||
|
|
578230e32c | ||
|
|
8559334339 | ||
|
|
8893d9edc4 | ||
|
|
43753ec113 | ||
|
|
f1fee1239b | ||
|
|
9772726065 | ||
|
|
8ecdde6cb5 | ||
|
|
5b3824917d | ||
|
|
ca4f10dc5e | ||
|
|
853fb33913 | ||
|
|
e352cfc861 | ||
|
|
b019ca0746 | ||
|
|
beb4e00afb | ||
|
|
9450305568 | ||
|
|
e18c64c9d9 | ||
|
|
7b018c60cb | ||
|
|
a81286c795 | ||
|
|
571e9bf26a | ||
|
|
c4714e95b6 | ||
|
|
d407e5556e | ||
|
|
6a3cfe54af | ||
|
|
a0bffe4a78 | ||
|
|
336c716a44 | ||
|
|
8810658858 | ||
|
|
337dfd5ee4 | ||
|
|
e37c9ed0a1 | ||
|
|
aa6a31eba5 | ||
|
|
6aa041b193 | ||
|
|
0fdc0a01d0 | ||
|
|
08cacc4943 | ||
|
|
87482e3746 | ||
|
|
8bb2d29a8d | ||
|
|
93039081d5 | ||
|
|
89ee28f858 | ||
|
|
5917786296 | ||
|
|
90fd323ac5 | ||
|
|
b6c384a0f7 | ||
|
|
cda8a7be38 | ||
|
|
ddbc35181c | ||
|
|
57dde3e980 | ||
|
|
3eba0c2297 | ||
|
|
414b7e28d3 | ||
|
|
fca464071f | ||
|
|
4f08f4b84c | ||
|
|
1b5175d018 | ||
|
|
0bfda6d4c8 | ||
|
|
880b22604b | ||
|
|
04a2dc075f | ||
|
|
01448c152c | ||
|
|
a09beb3833 | ||
|
|
feda1e6d84 | ||
|
|
4256bea418 | ||
|
|
4d47b098e5 | ||
|
|
163754a46c | ||
|
|
66b56416b6 | ||
|
|
c855346358 | ||
|
|
0e32c86c3d | ||
|
|
19952264c8 | ||
|
|
5ec1e97cae | ||
|
|
5f5746a2f6 | ||
|
|
d0ee6d1ad2 | ||
|
|
06c71eec65 | ||
|
|
aabc6c2825 | ||
|
|
8323458da9 | ||
|
|
d7c7ff1c12 | ||
|
|
d77c7d51e3 | ||
|
|
d51d0160d3 | ||
|
|
c2ad9d4996 | ||
|
|
79f828125d | ||
|
|
ad4b18cbbe | ||
|
|
1bd49671b7 | ||
|
|
9896057549 | ||
|
|
44832bbacb | ||
|
|
f20a923dd7 | ||
|
|
30403da326 | ||
|
|
6b68a76bbe | ||
|
|
8f10b58cb1 | ||
|
|
f8bc408abc | ||
|
|
f581f6163a | ||
|
|
88486a1278 | ||
|
|
9fcadc2d7c | ||
|
|
9ef6c57ca5 | ||
|
|
443d7684db | ||
|
|
a3ba7f0788 | ||
|
|
f083c0cba1 | ||
|
|
defa2d9df1 | ||
|
|
05c422ef23 | ||
|
|
51d274961b | ||
|
|
4b4cc04897 | ||
|
|
4bf3d4d87a | ||
|
|
71cc980e96 | ||
|
|
58c0b81908 | ||
|
|
3b42bd43ab | ||
|
|
a151532ffa | ||
|
|
a0d1ce77dc | ||
|
|
863cae1bab | ||
|
|
4010ea814a | ||
|
|
8e25c091f4 |
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/
|
||||
|
||||
127
.gitlab-ci.yml
127
.gitlab-ci.yml
@@ -1,8 +1,9 @@
|
||||
# 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
|
||||
|
||||
image: php:8.0
|
||||
|
||||
stages:
|
||||
- test
|
||||
@@ -36,38 +37,51 @@ before_script:
|
||||
- if [ -f /usr/local/etc/php/conf.d/z_prod.ini ]; then mv /usr/local/etc/php/conf.d/z_prod.ini /usr/local/etc/php/conf.d/z_prod.ini.off; fi
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- pecl install xdebug
|
||||
- apt-get update
|
||||
- apt-get install zip unzip libjpeg-dev libpng-dev -yqq
|
||||
- docker-php-ext-enable xdebug
|
||||
- docker-php-ext-install gd
|
||||
|
||||
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php ./composer.phar install --no-progress
|
||||
# php.ini settings
|
||||
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
|
||||
|
||||
# hidden job definition with template for PHP
|
||||
.job_template_php: &job_definition_php
|
||||
stage: test
|
||||
script:
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
|
||||
|
||||
# hidden job definition with template for MySQL/MariaDB
|
||||
.job_template_mysql: &job_definition_mysql
|
||||
stage: test
|
||||
script:
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
#.job_template_mysql: &job_definition_mysql
|
||||
# stage: test
|
||||
# script:
|
||||
# - echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
# - echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
# - echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
# - vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
|
||||
# hidden job definition with template for PostgreSQL
|
||||
.job_template_postgres: &job_definition_postgres
|
||||
stage: test
|
||||
services:
|
||||
- postgres:latest
|
||||
script:
|
||||
- export PGPASSWORD=$POSTGRES_PASSWORD
|
||||
- psql --version
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
|
||||
#.job_template_postgres: &job_definition_postgres
|
||||
# stage: test
|
||||
# services:
|
||||
# - postgres:latest
|
||||
# script:
|
||||
# - export PGPASSWORD=$POSTGRES_PASSWORD
|
||||
# - psql --version
|
||||
# - psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
|
||||
# Import hubzilla's DB schema
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
|
||||
# - psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
|
||||
# Show databases and relations/tables of hubzilla's database
|
||||
#- psql -h "postgres" -U "$POSTGRES_USER" -l
|
||||
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
|
||||
# Run the actual tests
|
||||
- vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
|
||||
# - vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
|
||||
|
||||
# hidden job definition with artifacts config template
|
||||
.artifacts_template:
|
||||
@@ -82,56 +96,61 @@ before_script:
|
||||
- tests/results/
|
||||
|
||||
|
||||
# PHP7.2 with MySQL 5.7
|
||||
php7.2_mysql5.7:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- mysql:5.7
|
||||
# PHP8.0
|
||||
php8.0:
|
||||
<<: *job_definition_php
|
||||
|
||||
# PHP8.0 with MySQL 5.7
|
||||
#php8.0_mysql5.7:
|
||||
# <<: *job_definition_mysql
|
||||
# services:
|
||||
# - mysql:5.7
|
||||
|
||||
|
||||
# PHP7.2 with MySQL 8 (latest)
|
||||
php7.2_mysql8:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- name: mysql:8
|
||||
command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
# PHP8.0 with MySQL 8 (latest)
|
||||
#php8.0_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:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- name: mariadb:10.2
|
||||
alias: mysql
|
||||
# PHP8.0 with MariaDB 10.2
|
||||
#php8.0_mariadb10.2:
|
||||
# <<: *job_definition_mysql
|
||||
# services:
|
||||
# - name: mariadb:10.2
|
||||
# alias: mysql
|
||||
|
||||
|
||||
# PHP7.3 with MariaDB 10.3 (latest)
|
||||
php7.3_mariadb10.3:
|
||||
<<: *job_definition_mysql
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
services:
|
||||
- name: mariadb:10.3
|
||||
alias: mysql
|
||||
|
||||
|
||||
# PHP7.2 with PostgreSQL latest (11)
|
||||
php7.2_postgres11:
|
||||
<<: *job_definition_postgres
|
||||
artifacts: *artifacts_template
|
||||
# PHP8.0 with MariaDB 10.3 (latest)
|
||||
#php8.0_mariadb10.3:
|
||||
# <<: *job_definition_mysql
|
||||
# image: php:8.0
|
||||
#image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
# services:
|
||||
# - name: mariadb:10.3
|
||||
# alias: mysql
|
||||
|
||||
|
||||
# PHP7.3 with PostgreSQL latest (11)
|
||||
php7.3_postgres11:
|
||||
<<: *job_definition_postgres
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
artifacts: *artifacts_template
|
||||
#php7.3_postgres11:
|
||||
# <<: *job_definition_postgres
|
||||
# artifacts: *artifacts_template
|
||||
|
||||
|
||||
# PHP7.3 with PostgreSQL latest (11)
|
||||
#php7.3_postgres11:
|
||||
# <<: *job_definition_postgres
|
||||
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
# artifacts: *artifacts_template
|
||||
|
||||
|
||||
# Generate Doxygen API Documentation and deploy it as GitLab pages
|
||||
pages:
|
||||
stage: deploy
|
||||
cache: {}
|
||||
image: php:7-cli-alpine
|
||||
image: php:8-cli-alpine
|
||||
before_script:
|
||||
- apk update
|
||||
- apk add doxygen ttf-freefont graphviz
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
|
||||
# How to use
|
||||
|
||||
## Disclaimers
|
||||
|
||||
- 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).
|
||||
- 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
|
||||
|
||||
@@ -15,9 +16,12 @@ Hardware
|
||||
|
||||
Software
|
||||
|
||||
+ Fresh installation of Debian 10 (Stretch)
|
||||
+ Fresh installation of Debian 10 (Buster)
|
||||
+ Router with open ports 80 and 443 for your web server
|
||||
|
||||
You can of course run the script on a VPS or any distant server as long as the above sotfware requirements are satisfied.
|
||||
|
||||
|
||||
## How to run the script
|
||||
|
||||
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
|
||||
@@ -25,29 +29,29 @@ Software
|
||||
- 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.
|
||||
- ./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
|
||||
|
||||
## Optional - Switch verification of email on/off
|
||||
|
||||
Do this just befor you register the user.
|
||||
Do this just before you register the first user.
|
||||
|
||||
In Admin settings of hubzilla or via terminal
|
||||
In Admin settings of your hub/instance or via terminal
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
@@ -61,18 +65,18 @@ Switch the verification on/off (1/0)
|
||||
|
||||
## What the script will do for you...
|
||||
|
||||
+ install everything required by Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||
+ 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 Hubzilla
|
||||
- update of your hub/instance (git)
|
||||
- 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
|
||||
- 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
|
||||
@@ -80,19 +84,12 @@ 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 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)
|
||||
|
||||
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
|
||||
@@ -101,17 +98,17 @@ The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzill
|
||||
|
||||
## 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
|
||||
|
||||
@@ -133,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 10.
|
||||
|
||||
It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
sudo raspi-config
|
||||
@@ -143,5 +138,6 @@ to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
## Reminder for Different Web Wervers
|
||||
|
||||
|
||||
For those of you who feel adventurous enough to use a different web server (i.e. Lighttpd...), don't forget that this script will install Apache or Nginx and that you can only have one web server listening to ports 80 & 443. Also, don't forget to tweak your daily shell script in /var/www/ accordingly.
|
||||
|
||||
@@ -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,656 +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,
|
||||
# * mariadb - the database for hubzilla,
|
||||
# * adminer,
|
||||
# * git to download and update 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)
|
||||
# - run letsencrypt to create, register and use a certifacte for https
|
||||
#
|
||||
#
|
||||
# Discussion
|
||||
# ----------
|
||||
#
|
||||
# Security - password is the same for mysql-server, phpmyadmin and hubzilla db
|
||||
# - The script runs into installation errors for phpmyadmin if it uses
|
||||
# different passwords. For the sake of simplicity one singel password.
|
||||
#
|
||||
# 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/ > 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 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/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 {
|
||||
print_info "stopping apache webserver..."
|
||||
systemctl stop apache2
|
||||
print_info "stopping mysql db..."
|
||||
systemctl stop mariadb
|
||||
}
|
||||
|
||||
function install_apache {
|
||||
print_info "installing apache..."
|
||||
nocheck_install "apache2 apache2-utils"
|
||||
a2enmod rewrite
|
||||
systemctl restart apache2
|
||||
}
|
||||
|
||||
function install_imagemagick {
|
||||
print_info "installing imagemagick..."
|
||||
nocheck_install "imagemagick"
|
||||
}
|
||||
|
||||
function install_curl {
|
||||
print_info "installing curl..."
|
||||
nocheck_install "curl"
|
||||
}
|
||||
|
||||
function install_wget {
|
||||
print_info "installing wget..."
|
||||
nocheck_install "wget"
|
||||
}
|
||||
|
||||
function install_sendmail {
|
||||
print_info "installing sendmail..."
|
||||
nocheck_install "sendmail sendmail-bin"
|
||||
}
|
||||
|
||||
function install_php {
|
||||
# openssl and mbstring are included in libapache2-mod-php
|
||||
print_info "installing php..."
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mysqli 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
|
||||
}
|
||||
|
||||
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('${db_root_password}') 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_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
|
||||
systemctl restart mariadb
|
||||
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
|
||||
if [ -z "$le_email" ]
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||
fi
|
||||
nocheck_install "certbot python-certbot-apache"
|
||||
print_info "run certbot ..."
|
||||
certbot --apache -w /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 addons..."
|
||||
cd /var/www/html/
|
||||
if git remote -v | grep -i "origin.*hubzilla.*core"
|
||||
then
|
||||
print_info "hubzilla"
|
||||
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
|
||||
elif git remote -v | grep -i "origin.*zap.*core"
|
||||
then
|
||||
print_info "zap"
|
||||
util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
|
||||
else
|
||||
die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla"
|
||||
fi
|
||||
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 "installed addons"
|
||||
}
|
||||
|
||||
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
|
||||
backup_mount_point=/media/hubzilla_backup
|
||||
|
||||
#set -x # activate debugging from here
|
||||
|
||||
check_config
|
||||
stop_hubzilla
|
||||
update_upgrade
|
||||
install_curl
|
||||
install_wget
|
||||
install_sendmail
|
||||
install_apache
|
||||
install_imagemagick
|
||||
install_php
|
||||
install_mysql
|
||||
install_adminer
|
||||
create_hubzilla_db
|
||||
run_freedns
|
||||
install_run_selfhost
|
||||
ping_domain
|
||||
configure_cron_freedns
|
||||
configure_cron_selfhost
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_letsencrypt
|
||||
configure_apache_for_https
|
||||
check_https
|
||||
else
|
||||
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
|
||||
fi
|
||||
|
||||
install_hubzilla
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
rewrite_to_https
|
||||
install_rsnapshot
|
||||
else
|
||||
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
|
||||
fi
|
||||
|
||||
configure_cron_daily
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_cryptosetup
|
||||
write_uninstall_script
|
||||
else
|
||||
print_info "is localhost - skipped installation of cryptosetup"
|
||||
fi
|
||||
|
||||
|
||||
#set +x # stop debugging from here
|
||||
|
||||
|
||||
144
.homeinstall/nginx-zotserver.conf.template
Normal file
144
.homeinstall/nginx-zotserver.conf.template
Normal file
@@ -0,0 +1,144 @@
|
||||
##
|
||||
# Hubzilla/Zap/Mistpark/Osada Nginx block configuration template
|
||||
# based on the example created by Olaf Conradi
|
||||
#
|
||||
# The files generated with this template will be added to
|
||||
# /etc/nginx/sites-available & /etc/nginx/sites-enabled (symlink)
|
||||
##
|
||||
|
||||
##
|
||||
# You should look at the following URL's in order to grasp a solid understanding
|
||||
# of Nginx configuration files in order to fully unleash the power of Nginx.
|
||||
#
|
||||
# http://wiki.nginx.org/Pitfalls
|
||||
# http://wiki.nginx.org/QuickStart
|
||||
# http://wiki.nginx.org/Configuration
|
||||
##
|
||||
|
||||
##
|
||||
# This configuration assumes
|
||||
# You filled the zotserver-config.txt file
|
||||
# Your domain/subdomain is functionnal
|
||||
# You want all traffic to be https
|
||||
# You have PHP FastCGI Process Manager (php-fpm) running on localhost
|
||||
##
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name SERVER_NAME;
|
||||
|
||||
# HTTP > HTTPS #
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
##
|
||||
# Configure Red with SSL
|
||||
#
|
||||
# All requests are routed to the front controller
|
||||
# except for certain known file types like images, css, etc.
|
||||
# Those are served statically whenever possible with a
|
||||
# fall back to the front controller (needed for avatars, for example)
|
||||
##
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name SERVER_NAME;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/letsencrypt/live/SERVER_NAME/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/SERVER_NAME/privkey.pem;
|
||||
ssl_session_timeout 5m;
|
||||
# DO WE NEED TO REVIEW THE FOLLOWING SETTINGS?
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
fastcgi_param HTTPS on;
|
||||
|
||||
charset utf-8;
|
||||
root INSTALL_PATH;
|
||||
index index.php;
|
||||
access_log /var/log/nginx/ZOTSERVER_LOG;
|
||||
|
||||
#Uncomment the following line to include a standard configuration file
|
||||
#Note that the most specific rule wins and your standard configuration
|
||||
#will therefore *add* to this file, but not override it.
|
||||
#include standard.conf
|
||||
|
||||
# allow uploads up to 20MB in size
|
||||
client_max_body_size 20m;
|
||||
client_body_buffer_size 128k;
|
||||
|
||||
include mime.types;
|
||||
|
||||
# rewrite to front controller as default rule
|
||||
location / {
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?req=$1;
|
||||
}
|
||||
}
|
||||
|
||||
# make sure webfinger and other well known services aren't blocked
|
||||
# by denying dot files and rewrite request to the front controller
|
||||
location ^~ /.well-known/ {
|
||||
allow all;
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?req=$1;
|
||||
}
|
||||
}
|
||||
|
||||
# statically serve these file types when possible
|
||||
# otherwise fall back to front controller
|
||||
# allow browser to cache them
|
||||
# added .htm for advanced source code editor library
|
||||
# location ~* \.(jpg|jpeg|gif|png|ico|css|js|htm|html|map|ttf|woff|woff2|svg)$ {
|
||||
# expires 30d;
|
||||
# try_files $uri /index.php?req=$uri&$args;
|
||||
# }
|
||||
# SHOULD WE UNCOMMENT THE ABOVE LINES ?
|
||||
|
||||
# block these file types
|
||||
location ~* \.(tpl|md|tgz|log|out)$ {
|
||||
deny all;
|
||||
}
|
||||
|
||||
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
|
||||
# or a unix socket
|
||||
location ~* \.php$ {
|
||||
# IS THE FOLLOWING STILL RELEVANT AS OF AUGUST 2020?
|
||||
# Zero-day exploit defense.
|
||||
# http://forum.nginx.org/read.php?2,88845,page=3
|
||||
# Won't work properly (404 error) if the file is not stored on this
|
||||
# server, which is entirely possible with php-fpm/php-fcgi.
|
||||
# Comment the 'try_files' line out if you set up php-fpm/php-fcgi on
|
||||
# another machine. And then cross your fingers that you won't get hacked.
|
||||
try_files $uri =404;
|
||||
|
||||
# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
|
||||
# With php5-cgi alone:
|
||||
# fastcgi_pass 127.0.0.1:9000;
|
||||
|
||||
# With php-fpm:
|
||||
fastcgi_pass unix:PHP_FPM_SOCK;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
}
|
||||
|
||||
# deny access to all dot files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
|
||||
#deny access to store
|
||||
|
||||
location ~ /store {
|
||||
deny all;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
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
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
|
||||
|
||||
|
||||
38
SBOM.md
Normal file
38
SBOM.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Hubzilla Software Bill of Materials - WIP
|
||||
|
||||
|Name|Version|License|Source|
|
||||
|----|-------|-------|------|
|
||||
|blueimp/jquery-file-upload|10.32.0.0|MIT|https://github.com/vkhramtsov/jQuery-File-Upload.git|
|
||||
|brick/math|0.9.3.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|
|
||||
|jbroadway/urlify|1.2.2.0|BSD-3-Clause-Clear|https://github.com/jbroadway/urlify.git|
|
||||
|league/html-to-markdown|5.0.1.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.33.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.2.2.0|MIT|https://github.com/ramsey/collection.git|
|
||||
|ramsey/uuid|4.2.3.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|
|
||||
|symfony/polyfill-php80|1.23.1.0|MIT|https://github.com/symfony/polyfill-php80.git|
|
||||
|symfony/polyfill-php81|1.23.0.0|MIT|https://github.com/symfony/polyfill-php81.git|
|
||||
|twbs/bootstrap|5.1.3.0|MIT|https://github.com/twbs/bootstrap.git|
|
||||
|voku/portable-ascii|1.5.6.0|MIT|https://github.com/voku/portable-ascii.git|
|
||||
|voku/stop-words|2.0.1.0|MIT|https://github.com/voku/stop-words.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|
|
||||
10
ServiceWorker.js
Normal file
10
ServiceWorker.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// This file should be served from the web root to avoid scope and cookie related issues with some browsers
|
||||
self.addEventListener('install', function(e) {
|
||||
console.log('install event');
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function(e) {
|
||||
// nothing here yet
|
||||
return;
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -140,6 +139,11 @@ class AccessList {
|
||||
* @param boolean $explicit (optional) default true
|
||||
*/
|
||||
function set_from_array($arr, $explicit = true) {
|
||||
$arr['contact_allow'] = $arr['contact_allow'] ?? [];
|
||||
$arr['group_allow'] = $arr['group_allow'] ?? [];
|
||||
$arr['contact_deny'] = $arr['contact_deny'] ?? [];
|
||||
$arr['group_deny'] = $arr['group_deny'] ?? [];
|
||||
|
||||
$this->allow_cid = perms2str((is_array($arr['contact_allow']))
|
||||
? $arr['contact_allow'] : explode(',', $arr['contact_allow']));
|
||||
$this->allow_gid = perms2str((is_array($arr['group_allow']))
|
||||
|
||||
@@ -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,15 +78,15 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class PermissionRoles {
|
||||
* @return number
|
||||
*/
|
||||
static public function version() {
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
static function role_perms($role) {
|
||||
@@ -27,6 +27,54 @@ class PermissionRoles {
|
||||
$ret['role'] = $role;
|
||||
|
||||
switch($role) {
|
||||
|
||||
case 'public':
|
||||
$ret['default_collection'] = false;
|
||||
$ret['perms_connect'] = [
|
||||
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki',
|
||||
'send_stream', 'post_comments', 'post_mail', 'post_wall', 'chat', 'post_like', 'republish'
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['limits']['post_comments'] = PERMS_AUTHED;
|
||||
$ret['limits']['post_mail'] = PERMS_AUTHED;
|
||||
$ret['limits']['post_like'] = PERMS_AUTHED;
|
||||
$ret['limits']['chat'] = PERMS_AUTHED;
|
||||
break;
|
||||
|
||||
// Hubzilla default role
|
||||
case 'personal':
|
||||
$ret['default_collection'] = true;
|
||||
$ret['perms_connect'] = [
|
||||
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki',
|
||||
'send_stream', 'post_comments', 'post_mail', 'chat', 'post_like'
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
$ret['default_collection'] = false;
|
||||
$ret['perms_connect'] = [
|
||||
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
|
||||
'view_pages', 'view_wiki', 'post_wall', 'post_comments',
|
||||
'post_mail', 'post_like', 'chat'
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['channel_type'] = 'group';
|
||||
break;
|
||||
|
||||
// Provide some defaults for the custom role so that we do not start
|
||||
// with no permissions at all if we create a new channel with this role
|
||||
case 'custom':
|
||||
$ret['default_collection'] = true;
|
||||
$ret['perms_connect'] = [
|
||||
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki',
|
||||
'send_stream', 'post_comments', 'post_mail', 'chat', 'post_like'
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
break;
|
||||
|
||||
/*
|
||||
case 'social':
|
||||
$ret['perms_auto'] = false;
|
||||
$ret['default_collection'] = false;
|
||||
@@ -100,6 +148,7 @@ class PermissionRoles {
|
||||
'post_mail', 'post_like' , 'republish', 'chat'
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['channel_type'] = 'group';
|
||||
|
||||
break;
|
||||
|
||||
@@ -113,6 +162,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 +182,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,15 +238,17 @@ class PermissionRoles {
|
||||
'post_mail', 'post_like' , 'republish', 'chat', 'write_wiki'
|
||||
];
|
||||
$ret['limits'] = PermissionLimits::Std_Limits();
|
||||
$ret['channel_type'] = 'group';
|
||||
|
||||
break;
|
||||
*/
|
||||
|
||||
case 'custom':
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$x = get_config('system','role_perms');
|
||||
|
||||
// let system settings over-ride any or all
|
||||
if($x && is_array($x) && array_key_exists($role,$x))
|
||||
$ret = array_merge($ret,$x[$role]);
|
||||
@@ -214,13 +267,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 +311,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;
|
||||
}
|
||||
@@ -280,6 +333,7 @@ class PermissionRoles {
|
||||
*/
|
||||
static public function roles() {
|
||||
$roles = [
|
||||
|
||||
t('Social Networking') => [
|
||||
'social_federation' => t('Social - Federation'),
|
||||
'social' => t('Social - Mostly Public'),
|
||||
@@ -313,4 +367,29 @@ class PermissionRoles {
|
||||
return $roles;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief Array with translated role names and grouping.
|
||||
*
|
||||
* Return an associative array with role names that can be used
|
||||
* to create select groups like in \e field_select_grouped.tpl.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function channel_roles() {
|
||||
$channel_roles = [
|
||||
//'public' => [t('Public'), t('A very permissive role suited for participation in the fediverse')],
|
||||
//'personal' => [t('Personal'), t('The $Projectname default role suited for a personal channel')],
|
||||
//'forum' => [t('Community forum'), t('This role configures your channel to act as an community forum')],
|
||||
//'custom' => [t('Custom'), t('This role comes with the presets of the personal role but allows you to configure it to your needs')]
|
||||
'public' => t('Public'),
|
||||
'personal' => t('Personal'),
|
||||
'group' => t('Community forum'),
|
||||
'custom' => t('Custom')
|
||||
];
|
||||
|
||||
call_hooks('list_channel_roles', $channel_roles);
|
||||
|
||||
return $channel_roles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class Permissions {
|
||||
* @return number
|
||||
*/
|
||||
static public function version() {
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,17 +65,17 @@ class Permissions {
|
||||
'write_wiki' => t('Can write to my wiki pages'),
|
||||
'post_wall' => t('Can post on my channel (wall) page'),
|
||||
'post_comments' => t('Can comment on or like my posts'),
|
||||
'post_mail' => t('Can send me private mail messages'),
|
||||
'post_mail' => t('Can send me direct messages'),
|
||||
'post_like' => t('Can like/dislike profiles and profile things'),
|
||||
'tag_deliver' => t('Can forward to all my channel connections via ! mentions in posts'),
|
||||
'chat' => t('Can chat with me'),
|
||||
'republish' => t('Can source my public posts in derived channels'),
|
||||
'republish' => t('Can source/mirror my public posts in derived channels'),
|
||||
//'tag_deliver' => t('Can forward to my contacts via direct messages (forum)'),
|
||||
'delegate' => t('Can administer my channel')
|
||||
];
|
||||
|
||||
$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,73 +215,85 @@ class Permissions {
|
||||
*/
|
||||
static public function connect_perms($channel_id) {
|
||||
|
||||
$my_perms = [];
|
||||
$permcat = null;
|
||||
$automatic = 0;
|
||||
$my_perms = [];
|
||||
$permcat = null;
|
||||
$automatic = get_pconfig($channel_id, 'system', 'autoperms');
|
||||
|
||||
// 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);
|
||||
$permcat = $pcp->fetch($pc);
|
||||
if($permcat && $permcat['perms']) {
|
||||
foreach($permcat['perms'] as $p) {
|
||||
$my_perms[$p['name']] = $p['value'];
|
||||
}
|
||||
$pc = get_pconfig($channel_id, 'system', 'default_permcat', 'default');
|
||||
$pcp = new Zlib\Permcat($channel_id);
|
||||
$permcat = $pcp->fetch($pc);
|
||||
if ($permcat && $permcat['perms']) {
|
||||
foreach ($permcat['perms'] as $p) {
|
||||
$my_perms[$p['name']] = $p['value'];
|
||||
}
|
||||
}
|
||||
|
||||
// look up the permission role to see if it specified auto-connect
|
||||
// and if there was no permcat or a default permcat, set the perms
|
||||
// from the role
|
||||
|
||||
$role = get_pconfig($channel_id,'system','permissions_role');
|
||||
if($role) {
|
||||
/*
|
||||
$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);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// If we reached this point without having any permission information,
|
||||
// it is likely a custom permissions role. First see if there are any
|
||||
// automatic permissions.
|
||||
|
||||
if(! $my_perms) {
|
||||
/*
|
||||
if (!$my_perms) {
|
||||
$m = Permissions::FilledAutoperms($channel_id);
|
||||
if($m) {
|
||||
if ($m) {
|
||||
$automatic = 1;
|
||||
$my_perms = $m;
|
||||
$my_perms = $m;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
// If we reached this point with no permissions, the channel is using
|
||||
// custom perms but they are not automatic. They will be stored in abconfig with
|
||||
// the channel's channel_hash (the 'self' connection).
|
||||
|
||||
if(! $my_perms) {
|
||||
/*
|
||||
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, 'role' => $pc]);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
static public function serialise($p) {
|
||||
$n = [];
|
||||
if ($p) {
|
||||
foreach ($p as $k => $v) {
|
||||
if (intval($v)) {
|
||||
$n[] = $k;
|
||||
}
|
||||
}
|
||||
}
|
||||
return implode(',', $n);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
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);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
|
||||
class Cache_embeds {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
@@ -20,8 +19,10 @@ class Cache_embeds {
|
||||
$item = $c[0];
|
||||
|
||||
// bbcode conversion by default processes embeds that aren't already cached.
|
||||
// Ignore the returned html output.
|
||||
// Ignore the returned html output.
|
||||
|
||||
bbcode($item['body']);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
38
Zotlabs/Daemon/Cache_query.php
Normal file
38
Zotlabs/Daemon/Cache_query.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?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);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
34
Zotlabs/Daemon/Channel_purge.php
Normal file
34
Zotlabs/Daemon/Channel_purge.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
class Channel_purge {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
cli_startup();
|
||||
|
||||
$channel_id = intval($argv[1]);
|
||||
|
||||
$channel = q("select * from channel where channel_id = %d and channel_removed = 1",
|
||||
intval($channel_id)
|
||||
);
|
||||
|
||||
if (! $channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
$r = q("select id from item where uid = %d and item_deleted = 0 limit 1000",
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rv) {
|
||||
drop_item($rv['id'], false);
|
||||
}
|
||||
}
|
||||
} while ($r);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2,39 +2,42 @@
|
||||
|
||||
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]))
|
||||
|
||||
$site_id = '';
|
||||
$sql_options = '';
|
||||
|
||||
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()),
|
||||
|
||||
@@ -9,6 +9,7 @@ class Cli_suggest {
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
update_suggestions();
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
77
Zotlabs/Daemon/Content_importer.php
Normal file
77
Zotlabs/Daemon/Content_importer.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\PConfig;
|
||||
|
||||
|
||||
require_once('include/cli_startup.php');
|
||||
require_once('include/attach.php');
|
||||
require_once('include/import.php');
|
||||
|
||||
class Content_importer {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
cli_startup();
|
||||
|
||||
$page = $argv[1];
|
||||
$since = $argv[2];
|
||||
$until = $argv[3];
|
||||
$channel_address = $argv[4];
|
||||
$hz_server = urldecode($argv[5]);
|
||||
|
||||
$m = parse_url($hz_server);
|
||||
|
||||
$channel = channelx_by_nick($channel_address);
|
||||
if(! $channel) {
|
||||
logger('channel not found');
|
||||
return;
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'X-API-Token' => random_string(),
|
||||
'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page ,
|
||||
'Host' => $m['host'],
|
||||
'(request-target)' => 'get /api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page ,
|
||||
];
|
||||
|
||||
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
|
||||
|
||||
$x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]);
|
||||
|
||||
// logger('item fetch: ' . print_r($x,true));
|
||||
|
||||
if(! $x['success']) {
|
||||
logger('no API response',LOGGER_DEBUG);
|
||||
killme();
|
||||
}
|
||||
|
||||
$j = json_decode($x['body'],true);
|
||||
|
||||
if(! is_array($j['item']) || ! count($j['item'])) {
|
||||
PConfig::Set($channel['channel_id'], 'import', 'content_completed', 1);
|
||||
return;
|
||||
}
|
||||
|
||||
$saved_notification_flags = notifications_off($channel['channel_id']);
|
||||
|
||||
import_items($channel,$j['item'],false,((array_key_exists('relocate',$j)) ? $j['relocate'] : null));
|
||||
|
||||
notifications_on($channel['channel_id'], $saved_notification_flags);
|
||||
|
||||
PConfig::Set($channel['channel_id'], 'import', 'content_progress', [
|
||||
'items_total' => $j['items_total'],
|
||||
'items_page' => $j['items_page'],
|
||||
'items_current_page' => count($j['item']),
|
||||
'last_page' => $page,
|
||||
'next_cmd' => ['Content_importer', sprintf('%d',$page + 1), $since, $until, $channel['channel_address'], urlencode($hz_server)]
|
||||
]);
|
||||
|
||||
$page++;
|
||||
|
||||
Master::Summon([ 'Content_importer', sprintf('%d',$page), $since, $until, $channel['channel_address'], urlencode($hz_server) ]);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
65
Zotlabs/Daemon/Convo.php
Normal file
65
Zotlabs/Daemon/Convo.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?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) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$message = Activity::fetch($message, $channel);
|
||||
}
|
||||
|
||||
// set client flag because comments will probably just be objects and not full blown activities
|
||||
// and that lets us use implied_create
|
||||
$AS = new ActivityStreams($message);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
Activity::store($channel, $contact['abook_xchan'], $AS, $item);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,45 +2,44 @@
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// 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
|
||||
|
||||
require_once('include/sharedwithme.php');
|
||||
apply_updates();
|
||||
|
||||
/**
|
||||
* Chatpresence: if somebody hasn't pinged recently, they've most likely left the page
|
||||
* and shouldn't count as online anymore. We allow an expection for bots.
|
||||
@@ -49,27 +48,29 @@ class Cron {
|
||||
db_utcnow(),
|
||||
db_quoteinterval('3 MINUTE')
|
||||
);
|
||||
|
||||
// expire any expired mail
|
||||
|
||||
q("delete from mail where expires > '%s' and expires < %s ",
|
||||
dbesc(NULL_DATE),
|
||||
db_utcnow()
|
||||
);
|
||||
require_once('include/account.php');
|
||||
remove_expired_registrations();
|
||||
|
||||
$interval = get_config('queueworker', 'queue_interval', 500000);
|
||||
|
||||
// expire any expired items
|
||||
|
||||
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
|
||||
$r = q("select id,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) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,9 +82,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']);
|
||||
}
|
||||
}
|
||||
@@ -93,33 +94,35 @@ 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) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clean expired photos from cache
|
||||
|
||||
|
||||
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
if($r) {
|
||||
if ($r) {
|
||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
foreach($r as $rr) {
|
||||
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);
|
||||
@@ -129,31 +132,35 @@ class Cron {
|
||||
|
||||
// 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) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,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) {
|
||||
foreach ($r as $rr) {
|
||||
$photos = import_xchan_photo($rr['xchan_photo_l'], $rr['xchan_hash'], false, true);
|
||||
$x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
|
||||
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]),
|
||||
@@ -209,36 +211,32 @@ class Cron {
|
||||
}
|
||||
|
||||
|
||||
// pull in some public posts
|
||||
// pull in some public posts if allowed
|
||||
|
||||
$disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
|
||||
if(! $disable_discover_tab)
|
||||
Master::Summon(array('Externals'));
|
||||
$disable_externals = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false || get_config('system', 'site_firehose');
|
||||
if (!$disable_externals)
|
||||
Master::Summon(['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)
|
||||
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
|
||||
@unlink($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'));
|
||||
}
|
||||
|
||||
@@ -50,10 +49,26 @@ class Cron_daily {
|
||||
dbesc('sse_id.%')
|
||||
);
|
||||
|
||||
// Mark items seen after X days (default 90)
|
||||
|
||||
$r = dbq("select channel_id from channel where channel_removed = 0");
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$mark_seen_days = get_pconfig($rr['channel_id'], 'system', 'mark_seen_days', 90);
|
||||
q("UPDATE item SET item_unseen = 0 WHERE
|
||||
uid = %d AND item_unseen = 1
|
||||
AND created < %s - INTERVAL %s",
|
||||
intval($rr['channel_id']),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($mark_seen_days . ' DAY')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up emdedded content cache
|
||||
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
|
||||
//update statistics in config
|
||||
@@ -67,8 +82,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",
|
||||
@@ -80,30 +95,31 @@ 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
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,35 +4,36 @@ 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
|
||||
// Find channels that were removed in the last three weeks, but
|
||||
// haven't been finally cleaned up. These should be older than 10
|
||||
// days to ensure that "purgeall" messages have gone out or bounced
|
||||
// or timed out.
|
||||
// days to ensure that "purgeall" messages have gone out or bounced
|
||||
// or timed out.
|
||||
|
||||
$r = q("select channel_id from channel where channel_removed = 1 and
|
||||
$r = q("select channel_id from channel where channel_removed = 1 and
|
||||
channel_deleted > %s - INTERVAL %s and channel_deleted < %s - INTERVAL %s",
|
||||
db_utcnow(), db_quoteinterval('21 DAY'),
|
||||
db_utcnow(), db_quoteinterval('10 DAY')
|
||||
);
|
||||
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'));
|
||||
|
||||
@@ -58,5 +59,6 @@ class Cron_weekly {
|
||||
* End Cron Weekly
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
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,9 +48,9 @@ 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);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,92 +2,34 @@
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,21 +2,22 @@
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
25
Zotlabs/Daemon/Delxitems.php
Normal file
25
Zotlabs/Daemon/Delxitems.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/connections.php');
|
||||
|
||||
/*
|
||||
* Daemon to remove 'item' resources in the background from a removed connection
|
||||
*/
|
||||
|
||||
class Delxitems {
|
||||
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
cli_startup();
|
||||
|
||||
if($argc != 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove_abook_items($argv[1], $argv[2]);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -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,35 @@ 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 +94,10 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,15 @@ 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');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,97 +2,155 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
require_once('include/zot.php');
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
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;
|
||||
$url = '';
|
||||
|
||||
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 {
|
||||
$networks = ['zot6'];
|
||||
|
||||
if (plugin_is_installed('pubcrawl')) {
|
||||
$networks[] = 'activitypub';
|
||||
}
|
||||
|
||||
stringify_array_elms($networks);
|
||||
$networks_str = implode(',', $networks);
|
||||
|
||||
$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 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),
|
||||
//dbesc('hubzilla%')
|
||||
//);
|
||||
|
||||
$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 * FROM hubloc
|
||||
LEFT JOIN abook ON abook_xchan = hubloc_hash
|
||||
LEFT JOIN site ON site_url = hubloc_url WHERE
|
||||
hubloc_network IN ( $networks_str ) AND
|
||||
abook_xchan IS NULL AND
|
||||
hubloc_url != '%s' AND
|
||||
hubloc_updated > '%s' AND
|
||||
hubloc_primary = 1 AND hubloc_deleted = 0 AND
|
||||
site_dead = 0
|
||||
ORDER BY $randfunc LIMIT 1",
|
||||
dbesc(z_root()),
|
||||
intval(DIRECTORY_MODE_STANDALONE),
|
||||
intval(SITE_TYPE_ZOT)
|
||||
datetime_convert('UTC', 'UTC', 'now - 30 days')
|
||||
);
|
||||
if($r)
|
||||
$url = $r[0]['site_url'];
|
||||
|
||||
if ($r) {
|
||||
$contact = $r[0];
|
||||
$url = $contact['hubloc_id_url'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$blacklisted = false;
|
||||
|
||||
if(! check_siteallowed($url)) {
|
||||
if (!check_siteallowed($contact['hubloc_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 > 5)
|
||||
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'));
|
||||
}
|
||||
$cl = Activity::get_actor_collections($contact['hubloc_hash']);
|
||||
if(empty($cl)) {
|
||||
$cl = get_xconfig($contact['hubloc_hash'], 'activitypub', 'collections');
|
||||
}
|
||||
|
||||
$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'] = '';
|
||||
$results = process_delivery(array('hash' => 'undefined'), get_item_elements($message),
|
||||
array(array('hash' => $sys['xchan_hash'])), false, true);
|
||||
$total ++;
|
||||
}
|
||||
logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG);
|
||||
}
|
||||
if (is_array($cl) && array_key_exists('outbox', $cl)) {
|
||||
$url = $cl['outbox'];
|
||||
}
|
||||
else {
|
||||
$url = str_replace('/channel/', '/outbox/', $contact['hubloc_id_url']);
|
||||
if ($url) {
|
||||
$url .= '?top=1';
|
||||
}
|
||||
}
|
||||
|
||||
if ($url) {
|
||||
logger('fetching outbox: ' . $url);
|
||||
|
||||
$obj = new ASCollection($url, $importer, 0, 10);
|
||||
$messages = $obj->get();
|
||||
|
||||
if ($messages) {
|
||||
foreach ($messages as $message) {
|
||||
if (is_string($message)) {
|
||||
$message = Activity::fetch($message, $importer);
|
||||
}
|
||||
|
||||
if ($message['type'] !== 'Create') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($contact['hubloc_network'] === 'zot6') {
|
||||
// make sure we only fetch top level items
|
||||
if (isset($message['object']['inReplyTo'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$obj_id = $message['object']['id'] ?? $message['object'];
|
||||
|
||||
Libzot::fetch_conversation($importer, $obj_id);
|
||||
$total++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$AS = new ActivityStreams($message);
|
||||
if ($AS->is_valid() && is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
Activity::store($importer, $contact['hubloc_hash'], $AS, $item);
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
logger('fetched messages count: ' . $total);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
71
Zotlabs/Daemon/File_importer.php
Normal file
71
Zotlabs/Daemon/File_importer.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\PConfig;
|
||||
|
||||
|
||||
require_once('include/cli_startup.php');
|
||||
require_once('include/attach.php');
|
||||
require_once('include/import.php');
|
||||
|
||||
class File_importer {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
cli_startup();
|
||||
|
||||
$page = $argv[1];
|
||||
$channel_address = $argv[2];
|
||||
$hz_server = urldecode($argv[3]);
|
||||
|
||||
$m = parse_url($hz_server);
|
||||
|
||||
$channel = channelx_by_nick($channel_address);
|
||||
if(! $channel) {
|
||||
logger('channel not found');
|
||||
return;
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'X-API-Token' => random_string(),
|
||||
'X-API-Request' => $hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page,
|
||||
'Host' => $m['host'],
|
||||
'(request-target)' => 'get /api/z/1.0/file/export_page?f=records=1&page=' . $page,
|
||||
];
|
||||
|
||||
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),true,'sha512');
|
||||
|
||||
// TODO: implement total count
|
||||
$x = z_fetch_url($hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page, false, $redirects, [ 'headers' => $headers ]);
|
||||
// logger('file fetch: ' . print_r($x,true));
|
||||
|
||||
if(! $x['success']) {
|
||||
logger('no API response',LOGGER_DEBUG);
|
||||
killme();
|
||||
}
|
||||
|
||||
$j = json_decode($x['body'],true);
|
||||
|
||||
if(! is_array($j['results'][0]['attach']) || ! count($j['results'][0]['attach'])) {
|
||||
PConfig::Set($channel['channel_id'], 'import', 'files_completed', 1);
|
||||
return;
|
||||
}
|
||||
|
||||
$r = sync_files($channel, $j['results']);
|
||||
|
||||
PConfig::Set($channel['channel_id'], 'import', 'files_progress', [
|
||||
'files_total' => $j['total'],
|
||||
'files_page' => 1, // export page atm returns just one file
|
||||
'last_page' => $page,
|
||||
'next_cmd' => ['File_importer',sprintf('%d',$page + 1), $channel['channel_address'], urlencode($hz_server)]
|
||||
]);
|
||||
|
||||
$page++;
|
||||
|
||||
Master::Summon([ 'File_importer',sprintf('%d',$page), $channel['channel_address'], urlencode($hz_server) ]);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2,32 +2,49 @@
|
||||
|
||||
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]);
|
||||
$is_webbie = false;
|
||||
$r = null;
|
||||
|
||||
if(! strpos($url,'@'))
|
||||
return;
|
||||
if (filter_var($url, FILTER_VALIDATE_EMAIL)) {
|
||||
$is_webbie = true;
|
||||
|
||||
$r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
|
||||
dbesc($url)
|
||||
);
|
||||
$r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($url)
|
||||
);
|
||||
}
|
||||
elseif (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
$r = q("select * from hubloc where hubloc_id_url = '%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) {
|
||||
if ($is_webbie) {
|
||||
$url = Webfinger::zot_url(punify($url));
|
||||
}
|
||||
|
||||
if ($url) {
|
||||
$zf = Zotfinger::exec($url, null);
|
||||
if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $url && intval($zf['signature']['header_valid'])) {
|
||||
Libzot::import_xchan($zf['data']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
16
Zotlabs/Daemon/Importdoc.php
Executable file → Normal file
16
Zotlabs/Daemon/Importdoc.php
Executable file → Normal file
@@ -5,31 +5,33 @@ namespace Zotlabs\Daemon;
|
||||
|
||||
class Importdoc {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
static public function run($argc, $argv) {
|
||||
|
||||
require_once('include/help.php');
|
||||
|
||||
self::update_docs_dir('doc/*');
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
static public function update_docs_dir($s) {
|
||||
$f = basename($s);
|
||||
$d = dirname($s);
|
||||
if($s === 'doc/html')
|
||||
if ($s === 'doc/html')
|
||||
return;
|
||||
$files = glob("$d/$f");
|
||||
if($files) {
|
||||
foreach($files as $fi) {
|
||||
if($fi === 'doc/html') {
|
||||
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,58 +2,69 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
if(array_search( __file__ , get_included_files()) === 0) {
|
||||
use Zotlabs\Lib\QueueWorker;
|
||||
|
||||
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);
|
||||
if ($argc)
|
||||
Master::Release($argc, $argv);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Master {
|
||||
|
||||
static public function Summon($arr) {
|
||||
|
||||
QueueWorker::Summon($arr);
|
||||
return;
|
||||
/*
|
||||
$hookinfo = [
|
||||
'argv'=>$arr
|
||||
'argv' => $arr
|
||||
];
|
||||
|
||||
call_hooks ('daemon_master_summon',$hookinfo);
|
||||
call_hooks('daemon_master_summon', $hookinfo);
|
||||
|
||||
$arr = $hookinfo['argv'];
|
||||
$arr = $hookinfo['argv'];
|
||||
$argc = count($arr);
|
||||
|
||||
if ((!is_array($arr) || (count($arr) < 1))) {
|
||||
logger("Summon handled by hook.",LOGGER_DEBUG);
|
||||
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);
|
||||
$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();
|
||||
|
||||
QueueWorker::Release($argv);
|
||||
return;
|
||||
/*
|
||||
$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))) {
|
||||
logger("Release handled by hook.",LOGGER_DEBUG);
|
||||
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,86 +2,97 @@
|
||||
|
||||
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)
|
||||
$importer = channelx_by_n($importer_uid);
|
||||
|
||||
if (!$importer)
|
||||
return;
|
||||
|
||||
$importer = $r[0];
|
||||
logger("onepoll: poll: ($contact_id) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
|
||||
|
||||
logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
|
||||
|
||||
$last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE))
|
||||
? datetime_convert('UTC','UTC','now - 7 days')
|
||||
: 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);
|
||||
$alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
||||
if ($alive) {
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
$alive = handle_feed($importer['channel_id'], $contact_id, $contact['xchan_hash']);
|
||||
|
||||
if (!$alive) {
|
||||
q("update abook set abook_updated = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
q("update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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),
|
||||
@@ -97,83 +108,87 @@ 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 = Activity::get_actor_collections($contact['abook_xchan']);
|
||||
if(empty($cl)) {
|
||||
$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/', '/outbox/', $contact['xchan_connurl']);
|
||||
}
|
||||
|
||||
logger('feed_update: ' . print_r($x,true), LOGGER_DATA);
|
||||
}
|
||||
if ($url) {
|
||||
logger('fetching outbox');
|
||||
$url = $url . '?date_begin=' . urlencode($last_update);
|
||||
|
||||
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($contact['xchan_network'] === 'zot6') {
|
||||
$url = $url . '&top=1';
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
if ($contact['xchan_network'] === 'zot6') {
|
||||
// make sure we only fetch top level items
|
||||
if ($message['type'] === 'Create' && !isset($message['object']['inReplyTo'])) {
|
||||
Libzot::fetch_conversation($importer, $message['object']['id']);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$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,204 +4,215 @@ 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 = get_config('queueworker', 'queue_interval', 500000);
|
||||
|
||||
/*
|
||||
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)
|
||||
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);
|
||||
|
||||
if ($t !== $c) {
|
||||
// if the last fetch failed only attempt fetch once a day
|
||||
$min = 60 * 24;
|
||||
}
|
||||
|
||||
$x = datetime_convert('UTC', 'UTC', "now - $min minutes");
|
||||
|
||||
if ($t < $x) {
|
||||
Master::Summon(['Onepoll', $contact['abook_id']]);
|
||||
|
||||
if ($interval) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(! 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) {
|
||||
usleep($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) {
|
||||
usleep($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_config('system','lastpoll',datetime_convert());
|
||||
|
||||
//All done - clear the lockfile
|
||||
set_config('system', 'lastpoll', datetime_convert());
|
||||
|
||||
//All done - clear the lockfile
|
||||
/*
|
||||
@unlink($lockfile);
|
||||
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,21 @@ 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);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,40 @@ 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);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
152
Zotlabs/Lib/ASCollection.php
Normal file
152
Zotlabs/Lib/ASCollection.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?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;
|
||||
|
||||
$data = null;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,17 @@ namespace Zotlabs\Lib;
|
||||
class AbConfig {
|
||||
|
||||
static public function Load($chan,$xhash,$family = '') {
|
||||
if($family)
|
||||
$where = '';
|
||||
|
||||
if($family) {
|
||||
$where = sprintf(" and cat = '%s' ",dbesc($family));
|
||||
}
|
||||
|
||||
$r = q("select * from abconfig where chan = %d and xchan = '%s' $where",
|
||||
intval($chan),
|
||||
dbesc($xhash)
|
||||
);
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
@@ -21,7 +26,7 @@ class AbConfig {
|
||||
intval($chan),
|
||||
dbesc($xhash),
|
||||
dbesc($family),
|
||||
dbesc($key)
|
||||
dbesc($key)
|
||||
);
|
||||
if($r) {
|
||||
return ((preg_match('|^a:[0-9]+:{.*}$|s', $r[0]['v'])) ? unserialize($r[0]['v']) : $r[0]['v']);
|
||||
@@ -41,19 +46,19 @@ class AbConfig {
|
||||
dbesc($xhash),
|
||||
dbesc($family),
|
||||
dbesc($key),
|
||||
dbesc($dbvalue)
|
||||
dbesc($dbvalue)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$r = q("update abconfig set v = '%s' where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
|
||||
dbesc($dbvalue),
|
||||
dbesc($dbvalue),
|
||||
dbesc($chan),
|
||||
dbesc($xhash),
|
||||
dbesc($family),
|
||||
dbesc($key)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if($r)
|
||||
return $value;
|
||||
return false;
|
||||
|
||||
383
Zotlabs/Lib/AccessList.php
Normal file
383
Zotlabs/Lib/AccessList.php
Normal file
@@ -0,0 +1,383 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
class AccessList {
|
||||
|
||||
static function add($uid, $name, $public = 0) {
|
||||
|
||||
$ret = false;
|
||||
$hash = '';
|
||||
if ($uid && $name) {
|
||||
$r = self::by_name($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 privacy group with this name was revived. Existing item permissions <strong>may</strong> apply to this privacy group and any future members. If this is not what you intended, please create another privacy group with a different name.') . EOL);
|
||||
}
|
||||
$hash = self::by_id($uid, $r);
|
||||
return $hash;
|
||||
}
|
||||
|
||||
$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) ? $hash : $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 by_name($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 by_hash($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 = 0) {
|
||||
if (!$gid) {
|
||||
$gid = self::by_name($uid, $name);
|
||||
}
|
||||
|
||||
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::by_name($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 profile_members_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 $rr) {
|
||||
$ret[] = $rr['xchan'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
static function select($uid, $options) {
|
||||
|
||||
$selected = $options['selected'] ?? '';
|
||||
$form_id = $options['form_id'] ?? 'accesslist_select';
|
||||
$label = $options['label'] ?? t('Select a privacy group');
|
||||
$before = $options['before'] ?? [];
|
||||
$after = $options['after'] ?? [];
|
||||
|
||||
$grps = [];
|
||||
$o = '';
|
||||
|
||||
$grps[] = [
|
||||
'name' => '',
|
||||
'id' => '0',
|
||||
'selected' => false
|
||||
];
|
||||
|
||||
if ($before) {
|
||||
$grps[] = $before;
|
||||
}
|
||||
|
||||
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
$grps[] = [
|
||||
'name' => $rr['gname'],
|
||||
'id' => $rr['hash'],
|
||||
'selected' => ($selected == $rr['hash'])
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($after) {
|
||||
$grps[] = $after;
|
||||
}
|
||||
|
||||
logger('select: ' . print_r($grps,true), LOGGER_DATA);
|
||||
|
||||
$o = replace_macros(get_markup_template('group_selection.tpl'), array(
|
||||
'$label' => $label,
|
||||
'$form_id' => $form_id,
|
||||
'$groups' => $grps
|
||||
));
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
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,25 @@ 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 $meta = 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,88 +37,96 @@ class ActivityStreams {
|
||||
*/
|
||||
function __construct($string) {
|
||||
|
||||
$this->raw = $string;
|
||||
if(!$string)
|
||||
return;
|
||||
|
||||
if(is_array($string)) {
|
||||
$this->raw = $string;
|
||||
|
||||
if (is_array($string)) {
|
||||
$this->data = $string;
|
||||
$this->raw = json_encode($string, JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
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'];
|
||||
$this->data['signed_data'] = $saved;
|
||||
if($ret['hubloc']) {
|
||||
$this->data['hubloc'] = $ret['hubloc'];
|
||||
if ($ret && $ret['success']) {
|
||||
if ($ret['signer']) {
|
||||
$saved = json_encode($this->data, JSON_UNESCAPED_SLASHES);
|
||||
$this->data = $tmp;
|
||||
$this->meta['signer'] = $ret['signer'];
|
||||
$this->meta['signed_data'] = $saved;
|
||||
if ($ret['hubloc']) {
|
||||
$this->meta['hubloc'] = $ret['hubloc'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This indicates only that we have sucessfully decoded JSON.
|
||||
$this->valid = true;
|
||||
|
||||
if(array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) {
|
||||
if($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
|
||||
// Special handling for Mastodon "delete actor" activities which will often fail to verify
|
||||
// because the key cannot be fetched. We will catch this condition elsewhere.
|
||||
if (is_array($this->data) && array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) {
|
||||
if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
|
||||
$this->deleted = $this->data['actor'];
|
||||
$this->valid = false;
|
||||
$this->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($this->is_valid()) {
|
||||
// Attempt to assemble an Activity from what we were given.
|
||||
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_actor('creator', $this->ldsig);
|
||||
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
|
||||
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// fetch recursive or embedded activities
|
||||
|
||||
if ($this->obj && is_array($this->obj) && array_key_exists('object',$this->obj)) {
|
||||
|
||||
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);
|
||||
if ($this->obj && is_array($this->obj) && isset($this->obj['actor']))
|
||||
$this->obj['actor'] = $this->get_actor('actor', $this->obj);
|
||||
if ($this->tgt && is_array($this->tgt) && isset($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) && isset($this->obj['inReplyTo'])) {
|
||||
$this->parent_id = $this->obj['inReplyTo'];
|
||||
}
|
||||
if((! $this->parent_id) && is_array($this->obj)) {
|
||||
if ((!$this->parent_id) && is_array($this->obj) && isset($this->obj['id'])) {
|
||||
$this->parent_id = $this->obj['id'];
|
||||
}
|
||||
}
|
||||
@@ -146,15 +154,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
|
||||
@@ -162,21 +175,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,33 +210,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 = '';
|
||||
}
|
||||
}
|
||||
@@ -243,14 +256,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;
|
||||
}
|
||||
|
||||
@@ -269,12 +282,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']));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,30 +306,27 @@ 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)) {
|
||||
|
||||
// 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",
|
||||
dbesc($x)
|
||||
);
|
||||
if($r) {
|
||||
$y = Activity::encode_person($r[0]);
|
||||
$y['cached'] = true;
|
||||
if ($this->is_url($x)) {
|
||||
$y = Activity::get_cached_actor($x);
|
||||
if ($y) {
|
||||
return $y;
|
||||
}
|
||||
}
|
||||
$actor = $this->get_compound_property($property,$base,$namespace,true);
|
||||
if(is_array($actor) && self::is_an_actor($actor['type'])) {
|
||||
if(array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) {
|
||||
|
||||
$actor = $this->get_compound_property($property, $base, $namespace, true);
|
||||
|
||||
if (is_array($actor) && self::is_an_actor($actor['type'])) {
|
||||
if (array_key_exists('id', $actor) && (!array_key_exists('inbox', $actor))) {
|
||||
$actor = $this->fetch_property($actor['id']);
|
||||
}
|
||||
return $actor;
|
||||
}
|
||||
return null;
|
||||
|
||||
return Activity::get_unknown_actor($this->data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -324,7 +341,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;
|
||||
@@ -332,23 +349,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'];
|
||||
$x['signed_data'] = $saved;
|
||||
if($ret['hubloc']) {
|
||||
$x['hubloc'] = $ret['hubloc'];
|
||||
if ($ret && $ret['success']) {
|
||||
if ($ret['signer']) {
|
||||
$saved = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$x = $tmp;
|
||||
$x['meta']['signer'] = $ret['signer'];
|
||||
$x['meta']['signed_data'] = $saved;
|
||||
if ($ret['hubloc']) {
|
||||
$x['meta']['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];
|
||||
}
|
||||
|
||||
@@ -362,7 +379,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;
|
||||
}
|
||||
|
||||
@@ -377,13 +394,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;
|
||||
}
|
||||
}
|
||||
@@ -397,18 +414,37 @@ 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) {
|
||||
|
||||
}
|
||||
$ret = '';
|
||||
|
||||
$hookdata = [];
|
||||
if ($channel)
|
||||
$hookdata['channel'] = $channel;
|
||||
|
||||
$hookdata['data'] = ['application/x-zot-activity+json'];
|
||||
|
||||
call_hooks('get_accept_header_string', $hookdata);
|
||||
|
||||
$ret = implode(', ', $hookdata['data']);
|
||||
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
|
||||
require_once('include/plugin.php');
|
||||
require_once('include/channel.php');
|
||||
|
||||
@@ -19,9 +21,10 @@ class Apps {
|
||||
* @brief
|
||||
*
|
||||
* @param boolean $translate (optional) default true
|
||||
* @param boolean $sync (optional) default false used if called from sync_sysapps()
|
||||
* @return array
|
||||
*/
|
||||
static public function get_system_apps($translate = true) {
|
||||
static public function get_system_apps($translate = true, $sync = false) {
|
||||
$ret = [];
|
||||
|
||||
if(is_dir('apps'))
|
||||
@@ -31,7 +34,7 @@ class Apps {
|
||||
|
||||
if($files) {
|
||||
foreach($files as $f) {
|
||||
$x = self::parse_app_description($f,$translate);
|
||||
$x = self::parse_app_description($f, $translate, $sync);
|
||||
if($x) {
|
||||
$ret[] = $x;
|
||||
}
|
||||
@@ -43,7 +46,7 @@ class Apps {
|
||||
$path = explode('/',$f);
|
||||
$plugin = trim($path[1]);
|
||||
if(plugin_is_installed($plugin)) {
|
||||
$x = self::parse_app_description($f,$translate);
|
||||
$x = self::parse_app_description($f, $translate, $sync);
|
||||
if($x) {
|
||||
$x['plugin'] = $plugin;
|
||||
$ret[] = $x;
|
||||
@@ -64,17 +67,17 @@ class Apps {
|
||||
static public function get_base_apps() {
|
||||
$x = get_config('system','base_apps',[
|
||||
'Connections',
|
||||
'Contact Roles',
|
||||
'Network',
|
||||
'Settings',
|
||||
'Files',
|
||||
'Channel Home',
|
||||
'View Profile',
|
||||
'Channel',
|
||||
'Photos',
|
||||
'Calendar',
|
||||
'Directory',
|
||||
'Search',
|
||||
'Help',
|
||||
'Profile Photo'
|
||||
'HQ',
|
||||
'Post'
|
||||
]);
|
||||
|
||||
/**
|
||||
@@ -156,7 +159,7 @@ class Apps {
|
||||
foreach(self::$available_apps as $iapp) {
|
||||
if($iapp['app_id'] == hash('whirlpool',$app['name'])) {
|
||||
$notfound = false;
|
||||
if(($iapp['app_version'] !== $app['version'])
|
||||
if((isset($app['version']) && $iapp['app_version'] !== $app['version'])
|
||||
|| ($app['plugin'] && (! $iapp['app_plugin']))) {
|
||||
return intval($iapp['app_id']);
|
||||
}
|
||||
@@ -205,9 +208,10 @@ class Apps {
|
||||
*
|
||||
* @param string $f filename
|
||||
* @param boolean $translate (optional) default true
|
||||
* @param boolean $sync (optional) default false
|
||||
* @return boolean|array
|
||||
*/
|
||||
static public function parse_app_description($f, $translate = true) {
|
||||
static public function parse_app_description($f, $translate = true, $sync = false) {
|
||||
$ret = [];
|
||||
$matches = [];
|
||||
|
||||
@@ -232,6 +236,7 @@ class Apps {
|
||||
$ret['photo'] = $baseurl . '/' . get_default_profile_photo(80);
|
||||
|
||||
$ret['type'] = 'system';
|
||||
$ret['plugin'] = '';
|
||||
|
||||
foreach($ret as $k => $v) {
|
||||
if(strpos($v,'http') === 0) {
|
||||
@@ -253,7 +258,7 @@ class Apps {
|
||||
if(array_key_exists('categories',$ret))
|
||||
$ret['categories'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['categories']);
|
||||
|
||||
if(array_key_exists('requires',$ret)) {
|
||||
if(array_key_exists('requires',$ret) && !$sync) {
|
||||
$requires = explode(',',$ret['requires']);
|
||||
foreach($requires as $require) {
|
||||
$require = trim(strtolower($require));
|
||||
@@ -305,14 +310,16 @@ class Apps {
|
||||
}
|
||||
}
|
||||
}
|
||||
if($ret) {
|
||||
if($translate)
|
||||
self::translate_system_apps($ret);
|
||||
|
||||
return $ret;
|
||||
if(empty($ret)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if($translate) {
|
||||
self::translate_system_apps($ret);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -338,7 +345,7 @@ class Apps {
|
||||
'Files' => t('Files'),
|
||||
'Webpages' => t('Webpages'),
|
||||
'Wiki' => t('Wiki'),
|
||||
'Channel Home' => t('Channel Home'),
|
||||
'Channel' => t('Channel'),
|
||||
'View Profile' => t('View Profile'),
|
||||
'Photos' => t('Photos'),
|
||||
'Calendar' => t('Calendar'),
|
||||
@@ -369,8 +376,7 @@ class Apps {
|
||||
'OAuth Apps Manager' => t('OAuth Apps Manager'),
|
||||
'OAuth2 Apps Manager' => t('OAuth2 Apps Manager'),
|
||||
'PDL Editor' => t('PDL Editor'),
|
||||
'Permission Categories' => t('Permission Categories'),
|
||||
'Premium Channel' => t('Premium Channel'),
|
||||
'Contact Roles' => t('Contact Roles'),
|
||||
'Public Stream' => t('Public Stream'),
|
||||
'My Chatrooms' => t('My Chatrooms'),
|
||||
'Channel Export' => t('Channel Export')
|
||||
@@ -421,7 +427,7 @@ class Apps {
|
||||
|
||||
self::translate_system_apps($papp);
|
||||
|
||||
if(trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
|
||||
if(isset($papp['plugin']) && trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
|
||||
return '';
|
||||
|
||||
$papp['papp'] = self::papp_encode($papp);
|
||||
@@ -516,14 +522,19 @@ class Apps {
|
||||
$hosturl = '';
|
||||
|
||||
if(local_channel()) {
|
||||
if(self::app_installed(local_channel(),$papp) && !$papp['deleted'])
|
||||
if(self::app_installed(local_channel(),$papp)) {
|
||||
$installed = true;
|
||||
}
|
||||
|
||||
if ($installed && isset($papp['deleted']) && $papp['deleted']) {
|
||||
$installed = false;
|
||||
}
|
||||
|
||||
$hosturl = z_root() . '/';
|
||||
}
|
||||
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) {
|
||||
@@ -535,13 +546,47 @@ class Apps {
|
||||
$install_action = (($installed) ? t('Update') : t('Install'));
|
||||
$icon = ((strpos($papp['photo'],'icon:') === 0) ? substr($papp['photo'],5) : '');
|
||||
|
||||
if (!$installed && $mode === 'module') {
|
||||
$_SESSION['return_url'] = App::$query_string;
|
||||
return replace_macros(get_markup_template('app_install.tpl'), [
|
||||
'$papp' => $papp,
|
||||
'$install' => $install_action
|
||||
]);
|
||||
}
|
||||
|
||||
if($mode === 'navbar') {
|
||||
return replace_macros(get_markup_template('app_nav_pinned.tpl'),array(
|
||||
'$app' => $papp,
|
||||
'$icon' => $icon,
|
||||
));
|
||||
}
|
||||
|
||||
if($mode === 'nav') {
|
||||
return replace_macros(get_markup_template('app_nav.tpl'),array(
|
||||
'$app' => $papp,
|
||||
'$icon' => $icon,
|
||||
));
|
||||
}
|
||||
|
||||
if($mode === 'inline') {
|
||||
return replace_macros(get_markup_template('app_inline.tpl'),array(
|
||||
'$app' => $papp,
|
||||
'$icon' => $icon,
|
||||
'$installed' => $installed,
|
||||
'$purchase' => ((isset($papp['page']) && (! $installed)) ? t('Purchase') : ''),
|
||||
'$action_label' => $install_action
|
||||
));
|
||||
}
|
||||
|
||||
if(in_array($mode, ['nav-order', 'nav-order-pinned'])) {
|
||||
return replace_macros(get_markup_template('app_order.tpl'),array(
|
||||
'$app' => $papp,
|
||||
'$icon' => $icon,
|
||||
'$hosturl' => $hosturl,
|
||||
'$mode' => $mode
|
||||
));
|
||||
}
|
||||
|
||||
if($mode === 'install') {
|
||||
$papp['embed'] = true;
|
||||
}
|
||||
@@ -550,20 +595,19 @@ 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') : ''),
|
||||
'$delete' => ((local_channel() && $mode == 'edit') ? t('Delete') : ''),
|
||||
'$undelete' => ((local_channel() && $mode == 'edit') ? t('Undelete') : ''),
|
||||
'$settings_url' => ((local_channel() && $installed && $mode == 'list') ? $papp['settings_url'] : ''),
|
||||
'$deleted' => $papp['deleted'],
|
||||
'$feature' => (($papp['embed'] || $mode == 'edit') ? false : true),
|
||||
'$pin' => (($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),
|
||||
'$settings_url' => ((local_channel() && $installed && $mode == 'list' && isset($papp['settings_url'])) ? $papp['settings_url'] : ''),
|
||||
'$deleted' => $papp['deleted'] ?? false,
|
||||
'$feature' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
|
||||
'$pin' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
|
||||
'$featured' => ((isset($papp['categories']) && strpos($papp['categories'], 'nav_featured_app') !== false) ? true : false),
|
||||
'$pinned' => ((isset($papp['categories']) && strpos($papp['categories'], 'nav_pinned_app') !== false) ? true : false),
|
||||
'$mode' => $mode,
|
||||
'$add' => t('Add to app-tray'),
|
||||
'$remove' => t('Remove from app-tray'),
|
||||
'$add_nav' => t('Pin to navbar'),
|
||||
@@ -572,6 +616,7 @@ class Apps {
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
static public function app_install($uid,$app) {
|
||||
|
||||
if(! is_array($app)) {
|
||||
@@ -586,10 +631,12 @@ class Apps {
|
||||
|
||||
$app['uid'] = $uid;
|
||||
|
||||
if(self::app_installed($uid,$app,true))
|
||||
if(self::app_installed($uid,$app,true)) {
|
||||
$x = self::app_update($app);
|
||||
else
|
||||
}
|
||||
else {
|
||||
$x = self::app_store($app);
|
||||
}
|
||||
|
||||
if($x['success']) {
|
||||
$r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
|
||||
@@ -597,13 +644,12 @@ class Apps {
|
||||
intval($uid)
|
||||
);
|
||||
if($r) {
|
||||
if(($app['uid']) && (! $r[0]['app_system'])) {
|
||||
if($app['categories'] && (! $app['term'])) {
|
||||
if($app['uid']) {
|
||||
if((isset($app['categories']) && $app['categories']) && !(isset($app['term']) && $app['term'])) {
|
||||
$r[0]['term'] = q("select * from term where otype = %d and oid = %d",
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($r[0]['id'])
|
||||
);
|
||||
build_sync_packet($uid,array('app' => $r[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -632,6 +678,7 @@ class Apps {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -643,38 +690,35 @@ class Apps {
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
if($x) {
|
||||
if(! intval($x[0]['app_deleted'])) {
|
||||
$x[0]['app_deleted'] = 1;
|
||||
if(self::can_delete($uid,$app)) {
|
||||
q("delete from app where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
q("delete from term where otype = %d and oid = %d",
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($x[0]['id'])
|
||||
);
|
||||
/**
|
||||
* @hooks app_destroy
|
||||
* Called after app entry got removed from database
|
||||
* and provide app array from database.
|
||||
*/
|
||||
call_hooks('app_destroy', $x[0]);
|
||||
}
|
||||
else {
|
||||
q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
}
|
||||
if(! intval($x[0]['app_system'])) {
|
||||
build_sync_packet($uid,array('app' => $x));
|
||||
}
|
||||
}
|
||||
else {
|
||||
self::app_undestroy($uid,$app);
|
||||
}
|
||||
|
||||
if($x && intval($x[0]['app_deleted'])) {
|
||||
self::app_undestroy($uid, $app);
|
||||
return;
|
||||
}
|
||||
|
||||
if(self::can_delete($uid,$app)) {
|
||||
q("delete from app where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
q("delete from term where otype = %d and oid = %d",
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($x[0]['id'])
|
||||
);
|
||||
|
||||
/**
|
||||
* @hooks app_destroy
|
||||
* Called after app entry got removed from database
|
||||
* and provide app array from database.
|
||||
*/
|
||||
call_hooks('app_destroy', $x[0]);
|
||||
}
|
||||
else {
|
||||
q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -691,13 +735,11 @@ class Apps {
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
if($x) {
|
||||
if($x[0]['app_system']) {
|
||||
q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
}
|
||||
if($x && intval($x[0]['app_deleted']) && $x[0]['app_system']) {
|
||||
q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -958,9 +1000,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;
|
||||
}
|
||||
}
|
||||
@@ -1151,7 +1190,7 @@ class Apps {
|
||||
$ret['success'] = true;
|
||||
$ret['app_id'] = $darray['app_id'];
|
||||
}
|
||||
if($arr['categories']) {
|
||||
if(isset($arr['categories']) && $arr['categories']) {
|
||||
$x = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
|
||||
dbesc($darray['app_id']),
|
||||
intval($darray['app_channel'])
|
||||
@@ -1159,9 +1198,9 @@ class Apps {
|
||||
$y = explode(',',$arr['categories']);
|
||||
if($y) {
|
||||
foreach($y as $t) {
|
||||
$t = trim($t);
|
||||
$t = escape_tags(trim($t));
|
||||
if($t) {
|
||||
store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t)));
|
||||
store_item_tag($darray['app_channel'], $x[0]['id'], TERM_OBJ_APP, TERM_CATEGORY, $t, z_root() . '/apps/?f=&cat=' . $t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1249,7 +1288,7 @@ class Apps {
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($x[0]['id'])
|
||||
);
|
||||
if($arr['categories']) {
|
||||
if(isset($arr['categories']) && $arr['categories']) {
|
||||
$y = explode(',',$arr['categories']);
|
||||
if($y) {
|
||||
foreach($y as $t) {
|
||||
@@ -1277,58 +1316,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)
|
||||
@@ -1357,4 +1396,17 @@ class Apps {
|
||||
return chunk_split(base64_encode(json_encode($papp)),72,"\n");
|
||||
}
|
||||
|
||||
static public function get_papp($app) {
|
||||
|
||||
$r = q("select * from app where app_id = '%s' and app_channel = 0 limit 1",
|
||||
dbesc(hash('whirlpool', $app))
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$papp = self::app_encode($r[0]);
|
||||
return $papp;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'])
|
||||
|
||||
316
Zotlabs/Lib/Connect.php
Normal file
316
Zotlabs/Lib/Connect.php
Normal file
@@ -0,0 +1,316 @@
|
||||
<?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 LEFT JOIN hubloc ON xchan_hash = hubloc_hash WHERE ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ORDER BY hubloc_id DESC",
|
||||
dbesc($url),
|
||||
dbesc($url),
|
||||
dbesc($url)
|
||||
);
|
||||
|
||||
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;
|
||||
$wf = 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) {
|
||||
|
||||
$xchan_hash = (($wf) ? $wf : $url);
|
||||
|
||||
// something was discovered - find the record which was just created.
|
||||
|
||||
$r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' ) $sql_options",
|
||||
dbesc($xchan_hash),
|
||||
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() : ''),
|
||||
'abook_role' => get_pconfig($uid, 'system', 'default_permcat', 'default')
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
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::by_hash($uid,$default_group);
|
||||
if ($g) {
|
||||
AccessList::member_add($uid,'',$xchan_hash,$g['id']);
|
||||
}
|
||||
}
|
||||
|
||||
$result['success'] = true;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
210
Zotlabs/Lib/Crypto.php
Normal file
210
Zotlabs/Lib/Crypto.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
if (!$alg) {
|
||||
$alg = 'sha256';
|
||||
}
|
||||
|
||||
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,37 @@ 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!>');
|
||||
|
||||
if ($params['type'] == NOTIFY_MAIL) {
|
||||
logger('notification: mail');
|
||||
$subject = sprintf( t('[$Projectname:Notify] New mail received at %s'),$sitename);
|
||||
$parent_mid = '';
|
||||
$parent_item = [];
|
||||
|
||||
$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'];
|
||||
// @@TODO: consider using switch instead of those elseif
|
||||
if (isset($params['type']) && $params['type'] == NOTIFY_MAIL) {
|
||||
logger('notification: mail');
|
||||
$subject = sprintf( t('[$Projectname:Notify] New direct message received at %s'), $sitename);
|
||||
|
||||
$preamble = sprintf( t('%1$s sent you a new direct message at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$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 (isset($params['type']) && $params['type'] === NOTIFY_COMMENT) {
|
||||
//logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
|
||||
|
||||
$moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false);
|
||||
@@ -143,28 +147,34 @@ 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');
|
||||
|
||||
}
|
||||
|
||||
$parent_mid = $params['parent_mid'];
|
||||
$parent_mid = $params['parent_mid'] ?? '';
|
||||
|
||||
// Check to see if there was already a notify for this post.
|
||||
// If so don't create a second notification
|
||||
|
||||
$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 +184,7 @@ class Enotify {
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if it's a post figure out who's post it is.
|
||||
|
||||
@@ -189,6 +199,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 +223,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 +234,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,28 +251,27 @@ 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 (isset($params['type']) && $params['type'] === NOTIFY_LIKE) {
|
||||
// logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
|
||||
|
||||
$itemlink = $params['link'];
|
||||
|
||||
if (array_key_exists('item',$params) && (! activity_match($params['item']['verb'],ACTIVITY_LIKE))) {
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
|
||||
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ACTIVITY_LIKE) || activity_match($params['item']['verb'], ACTIVITY_DISLIKE))) {
|
||||
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
|
||||
logger('notification: not a visible activity. Ignoring.');
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$parent_mid = $params['parent_mid'];
|
||||
$parent_mid = $params['parent_mid'] ?? '';
|
||||
|
||||
// Check to see if there was already a notify for this post.
|
||||
// If so don't create a second notification
|
||||
|
||||
$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 +281,7 @@ class Enotify {
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if it's a post figure out who's post it is.
|
||||
|
||||
@@ -284,8 +294,12 @@ class Enotify {
|
||||
);
|
||||
}
|
||||
|
||||
xchan_query($p);
|
||||
if (!$p) {
|
||||
pop_lang();
|
||||
return;
|
||||
}
|
||||
|
||||
xchan_query($p);
|
||||
|
||||
$item_post_type = item_post_type($p[0]);
|
||||
// $private = $p[0]['item_private'];
|
||||
@@ -293,13 +307,16 @@ class Enotify {
|
||||
|
||||
$parent_item = $p[0];
|
||||
|
||||
$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked'));
|
||||
|
||||
// "your post"
|
||||
if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
|
||||
$dest_str = sprintf(t('%1$s liked [zrl=%2$s]your %3$s[/zrl]'),
|
||||
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]'),
|
||||
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
|
||||
$verb,
|
||||
$itemlink,
|
||||
$item_post_type);
|
||||
$item_post_type
|
||||
);
|
||||
else {
|
||||
pop_lang();
|
||||
return;
|
||||
@@ -307,12 +324,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 +338,14 @@ class Enotify {
|
||||
|
||||
|
||||
|
||||
if($params['type'] == NOTIFY_WALL) {
|
||||
elseif(isset($params['type']) && $params['type'] === NOTIFY_WALL) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] %s posted to your profile wall') , $sender['xchan_name']);
|
||||
|
||||
$preamble = sprintf( t('%1$s posted to your profile wall at %2$s') , $sender['xchan_name'], $sitename);
|
||||
|
||||
$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 +353,8 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_TAGSELF) {
|
||||
elseif (isset($params['type']) && $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 +364,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 +377,12 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_POKE) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_POKE) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] %1$s poked you') , $sender['xchan_name']);
|
||||
$preamble = sprintf( t('%1$s poked you at %2$s') , $sender['xchan_name'], $sitename);
|
||||
$epreamble = sprintf( t('%1$s [zrl=%2$s]poked you[/zrl].') ,
|
||||
'[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 +394,12 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_TAGSHARE) {
|
||||
elseif (isset($params['type']) && $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 +407,12 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_INTRO) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_INTRO) {
|
||||
$subject = sprintf( t('[$Projectname:Notify] Introduction received'));
|
||||
$preamble = sprintf( t('You\'ve received an new connection request from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
|
||||
$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 +421,13 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_SUGGEST) {
|
||||
elseif (isset($params['type']) && $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 +439,11 @@ class Enotify {
|
||||
$itemlink = $params['link'];
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_CONFIRM) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_CONFIRM) {
|
||||
// ?
|
||||
}
|
||||
|
||||
if ($params['type'] == NOTIFY_SYSTEM) {
|
||||
elseif (isset($params['type']) && $params['type'] === NOTIFY_SYSTEM) {
|
||||
// ?
|
||||
}
|
||||
|
||||
@@ -455,7 +471,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 +486,7 @@ class Enotify {
|
||||
} while ($dups === true);
|
||||
|
||||
|
||||
$datarray = array();
|
||||
$datarray = [];
|
||||
$datarray['hash'] = $hash;
|
||||
$datarray['sender_hash'] = $sender['xchan_hash'];
|
||||
$datarray['xname'] = $sender['xchan_name'];
|
||||
@@ -482,12 +498,13 @@ class Enotify {
|
||||
$datarray['link'] = $itemlink;
|
||||
$datarray['parent'] = $parent_mid;
|
||||
$datarray['parent_item'] = $parent_item;
|
||||
$datarray['ntype'] = $params['type'];
|
||||
$datarray['verb'] = $params['verb'];
|
||||
$datarray['otype'] = $params['otype'];
|
||||
$datarray['ntype'] = $params['type'] ?? '';
|
||||
$datarray['verb'] = $params['verb'] ?? '';
|
||||
$datarray['otype'] = $params['otype'] ?? '';
|
||||
$datarray['abort'] = false;
|
||||
$datarray['seen'] = 0;
|
||||
|
||||
$datarray['item'] = $params['item'];
|
||||
$datarray['item'] = $params['item'] ?? [];
|
||||
|
||||
call_hooks('enotify_store', $datarray);
|
||||
|
||||
@@ -498,17 +515,16 @@ class Enotify {
|
||||
|
||||
|
||||
// create notification entry in DB
|
||||
$seen = 0;
|
||||
|
||||
// Mark some notifications as seen right away
|
||||
// Note! The notification have to be created, because they are used to send emails
|
||||
// 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)) {
|
||||
$seen = 1;
|
||||
if (($params['type'] === NOTIFY_WALL) || ($params['type'] === NOTIFY_MAIL) || ($params['type'] === NOTIFY_INTRO)) {
|
||||
$datarray['seen'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,7 +540,7 @@ class Enotify {
|
||||
intval($datarray['uid']),
|
||||
dbesc($datarray['link']),
|
||||
dbesc($datarray['parent']),
|
||||
intval($seen),
|
||||
intval($datarray['seen']),
|
||||
intval($datarray['ntype']),
|
||||
dbesc($datarray['verb']),
|
||||
dbesc($datarray['otype'])
|
||||
@@ -543,12 +559,12 @@ 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;
|
||||
@@ -568,7 +584,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();
|
||||
@@ -577,15 +593,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);
|
||||
|
||||
@@ -594,14 +610,14 @@ class Enotify {
|
||||
unset($_SESSION['zid_override']);
|
||||
unset($_SESSION['zrl_override']);
|
||||
|
||||
$datarray = array();
|
||||
$datarray = [];
|
||||
$datarray['banner'] = $banner;
|
||||
$datarray['product'] = $product;
|
||||
$datarray['preamble'] = $preamble;
|
||||
$datarray['sitename'] = $sitename;
|
||||
$datarray['siteurl'] = $siteurl;
|
||||
$datarray['type'] = $params['type'];
|
||||
$datarray['parent'] = $params['parent_mid'];
|
||||
$datarray['type'] = $params['type'] ?? '';
|
||||
$datarray['parent'] = $params['parent_mid'] ?? '';
|
||||
$datarray['source_name'] = $sender['xchan_name'];
|
||||
$datarray['source_link'] = $sender['xchan_url'];
|
||||
$datarray['source_photo'] = $sender['xchan_photo_s'];
|
||||
@@ -668,7 +684,6 @@ class Enotify {
|
||||
'$source_name' => $datarray['source_name'],
|
||||
'$source_link' => $datarray['source_link'],
|
||||
'$source_photo' => $datarray['source_photo'],
|
||||
'$username' => $datarray['to_name'],
|
||||
'$hsitelink' => $datarray['hsitelink'],
|
||||
'$hitemlink' => $datarray['hitemlink'],
|
||||
'$thanks' => $datarray['thanks'],
|
||||
@@ -690,7 +705,6 @@ class Enotify {
|
||||
'$source_name' => $datarray['source_name'],
|
||||
'$source_link' => $datarray['source_link'],
|
||||
'$source_photo' => $datarray['source_photo'],
|
||||
'$username' => $datarray['to_name'],
|
||||
'$tsitelink' => $datarray['tsitelink'],
|
||||
'$titemlink' => $datarray['titemlink'],
|
||||
'$thanks' => $datarray['thanks'],
|
||||
@@ -747,21 +761,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
|
||||
@@ -769,15 +783,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(
|
||||
@@ -786,7 +800,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;
|
||||
}
|
||||
|
||||
@@ -796,16 +810,16 @@ 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
|
||||
|
||||
localize_item($item);
|
||||
|
||||
if($item['shortlocalize']) {
|
||||
if(isset($item['shortlocalize'])) {
|
||||
$itemem_text = $item['shortlocalize'];
|
||||
}
|
||||
elseif($item['localize']) {
|
||||
elseif(isset($item['localize'])) {
|
||||
$itemem_text = $item['localize'];
|
||||
}
|
||||
else {
|
||||
@@ -818,18 +832,28 @@ class Enotify {
|
||||
$itemem_text = sprintf( t('repeated %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
|
||||
}
|
||||
|
||||
if($item['verb'] === ACTIVITY_LIKE) {
|
||||
$itemem_text = sprintf( t('liked %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
|
||||
}
|
||||
|
||||
if($item['verb'] === ACTIVITY_DISLIKE) {
|
||||
$itemem_text = sprintf( t('disliked %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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -837,27 +861,31 @@ class Enotify {
|
||||
// convert this logic into a json array just like the system notifications
|
||||
|
||||
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
|
||||
$body = html2plain(bbcode($item['body'], ['drop_media' => true, 'tryoembed' => false]), 75, true);
|
||||
if ($body) {
|
||||
$body = htmlentities($body, ENT_QUOTES, 'UTF-8', false);
|
||||
}
|
||||
|
||||
$x = array(
|
||||
'notify_link' => $item['llink'],
|
||||
'name' => $item[$who]['xchan_name'],
|
||||
'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']),
|
||||
'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' => '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'])),
|
||||
'notify_id' => 'undefined',
|
||||
'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''),
|
||||
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])),
|
||||
'thread_top' => (($item['item_thread_top']) ? true : false),
|
||||
'message' => bbcode(escape_tags($itemem_text)),
|
||||
'body' => $body,
|
||||
// these are for the superblock addon
|
||||
'hash' => $item[$who]['xchan_hash'],
|
||||
'uid' => $item['uid'],
|
||||
'display' => true
|
||||
);
|
||||
|
||||
call_hooks('enotify_format',$x);
|
||||
call_hooks('enotify_format', $x);
|
||||
if(! $x['display']) {
|
||||
return [];
|
||||
}
|
||||
@@ -874,17 +902,16 @@ class Enotify {
|
||||
|
||||
$mid = basename($tt['link']);
|
||||
|
||||
$b64mid = ((strpos($mid, 'b64.') === 0) ? $mid : 'b64.' . base64url_encode($mid));
|
||||
|
||||
$b64mid = gen_link_id($mid);
|
||||
$x = [
|
||||
'notify_link' => z_root() . '/notify/view/' . $tt['id'],
|
||||
'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 : 'undefined'),
|
||||
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'),
|
||||
'b64mid' => (($tt['otype'] == 'item') ? $b64mid : ''),
|
||||
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''),
|
||||
'message' => $message
|
||||
];
|
||||
|
||||
@@ -894,8 +921,8 @@ class Enotify {
|
||||
|
||||
static public function format_intros($rr) {
|
||||
|
||||
$x = [
|
||||
'notify_link' => z_root() . '/connections/ifpending',
|
||||
return [
|
||||
'notify_link' => z_root() . '/connections#' . $rr['abook_id'],
|
||||
'name' => $rr['xchan_name'],
|
||||
'addr' => $rr['xchan_addr'],
|
||||
'url' => $rr['xchan_url'],
|
||||
@@ -905,13 +932,11 @@ class Enotify {
|
||||
'message' => t('added your channel')
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_files($rr) {
|
||||
|
||||
$x = [
|
||||
return [
|
||||
'notify_link' => z_root() . '/sharedwithme',
|
||||
'name' => $rr['author']['xchan_name'],
|
||||
'addr' => $rr['author']['xchan_addr'],
|
||||
@@ -922,13 +947,11 @@ class Enotify {
|
||||
'message' => t('shared a file with you')
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_mail($rr) {
|
||||
|
||||
$x = [
|
||||
return [
|
||||
'notify_link' => z_root() . '/mail/' . $rr['id'],
|
||||
'name' => $rr['xchan_name'],
|
||||
'addr' => $rr['xchan_addr'],
|
||||
@@ -936,11 +959,9 @@ class Enotify {
|
||||
'photo' => $rr['xchan_photo_s'],
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']),
|
||||
'hclass' => (intval($rr['mail_seen']) ? 'notify-seen' : 'notify-unseen'),
|
||||
'message' => t('sent you a private message'),
|
||||
'message' => t('sent you a direct message'),
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_all_events($rr) {
|
||||
@@ -950,35 +971,31 @@ class Enotify {
|
||||
$today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false);
|
||||
$when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
|
||||
|
||||
$x = [
|
||||
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' => ('notify-unseen'),
|
||||
'message' => t('posted an event')
|
||||
'hclass' => (($today) ? 'notify-unseen bg-warning' : 'notify-unseen'),
|
||||
'message' => t('created an event')
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static public function format_register($rr) {
|
||||
|
||||
$x = [
|
||||
return [
|
||||
'notify_link' => z_root() . '/admin/accounts',
|
||||
'name' => $rr['account_email'],
|
||||
'addr' => $rr['account_email'],
|
||||
'url' => '',
|
||||
'name' => $rr['reg_did2'],
|
||||
//'addr' => '',
|
||||
'photo' => z_root() . '/' . get_default_profile_photo(48),
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(),$rr['account_created']),
|
||||
'when' => datetime_convert('UTC', date_default_timezone_get(),$rr['reg_created']),
|
||||
'hclass' => ('notify-unseen'),
|
||||
'message' => t('requires approval')
|
||||
'message' => t('status verified')
|
||||
];
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,405 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
|
||||
class Group {
|
||||
|
||||
static function add($uid,$name,$public = 0) {
|
||||
|
||||
$ret = false;
|
||||
if(x($uid) && x($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 group which we once deleted
|
||||
// all the old members are gone, but the group remains so we don't break any security
|
||||
// access lists. What we're doing here is reviving the dead group, but old content which
|
||||
// was restricted to this group may now be seen by the new group 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 group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name.') . EOL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
do {
|
||||
$dups = false;
|
||||
$hash = random_string(32) . str_replace(['<','>'],['.','.'], $name);
|
||||
|
||||
$r = q("SELECT id FROM pgrp WHERE hash = '%s' LIMIT 1", dbesc($hash));
|
||||
if($r)
|
||||
$dups = true;
|
||||
} while($dups == true);
|
||||
|
||||
|
||||
$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(x($uid) && x($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'];
|
||||
}
|
||||
|
||||
if(! $group_id)
|
||||
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 = $r[0];
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
static function byname($uid,$name) {
|
||||
if((! $uid) || (! strlen($name)))
|
||||
return false;
|
||||
$r = q("SELECT * FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
|
||||
intval($uid),
|
||||
dbesc($name)
|
||||
);
|
||||
if($r)
|
||||
return $r[0]['id'];
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static function rec_byhash($uid,$hash) {
|
||||
if((! $uid) || (! strlen($hash)))
|
||||
return false;
|
||||
$r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1",
|
||||
intval($uid),
|
||||
dbesc($hash)
|
||||
);
|
||||
if($r)
|
||||
return $r[0];
|
||||
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
|
||||
if(! $r)
|
||||
$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($gid) {
|
||||
$ret = array();
|
||||
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(local_channel()),
|
||||
intval(local_channel())
|
||||
);
|
||||
if($r)
|
||||
$ret = $r;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
static function members_xchan($gid) {
|
||||
$ret = [];
|
||||
if(intval($gid)) {
|
||||
$r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d",
|
||||
intval($gid),
|
||||
intval(local_channel())
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
$ret[] = $rr['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 $rr) {
|
||||
$ret[] = $rr['xchan'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static function select($uid,$group = '') {
|
||||
|
||||
$grps = [];
|
||||
$o = '';
|
||||
|
||||
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
|
||||
intval($uid)
|
||||
);
|
||||
$grps[] = array('name' => '', 'hash' => '0', 'selected' => '');
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
$grps[] = array('name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : ''));
|
||||
}
|
||||
|
||||
}
|
||||
logger('select: ' . print_r($grps,true), LOGGER_DATA);
|
||||
|
||||
$o = replace_macros(get_markup_template('group_selection.tpl'), array(
|
||||
'$label' => t('Add new connections to this privacy group'),
|
||||
'$groups' => $grps
|
||||
));
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static function widget($every="connections",$each="group",$edit = false, $group_id = 0, $cid = '',$mode = 1) {
|
||||
|
||||
$o = '';
|
||||
|
||||
if(! (local_channel() && feature_enabled(local_channel(),'groups'))) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$groups = array();
|
||||
|
||||
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
|
||||
intval($_SESSION['uid'])
|
||||
);
|
||||
$member_of = array();
|
||||
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' => "group/".$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),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$tpl = get_markup_template("group_side.tpl");
|
||||
$o = replace_macros($tpl, array(
|
||||
'$title' => t('Privacy Groups'),
|
||||
'$edittext' => t('Edit group'),
|
||||
'$createtext' => t('Add privacy group'),
|
||||
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''),
|
||||
'$groups' => $groups,
|
||||
'$add' => t('add'),
|
||||
));
|
||||
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
static function expand($g) {
|
||||
if(! (is_array($g) && count($g)))
|
||||
return array();
|
||||
|
||||
$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 $rr) {
|
||||
$ret[] = $rr['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 = array();
|
||||
if($r) {
|
||||
foreach($r as $rr)
|
||||
$ret[] = $rr['gid'];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -35,11 +35,11 @@ class LDSignatures {
|
||||
|
||||
$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);
|
||||
|
||||
@@ -75,29 +75,31 @@ class LDSignatures {
|
||||
}
|
||||
|
||||
static function hash($obj) {
|
||||
|
||||
return hash('sha256',self::normalise($obj));
|
||||
return hash('sha256', self::normalise($obj));
|
||||
}
|
||||
|
||||
static function normalise($data) {
|
||||
$ret = '';
|
||||
|
||||
if(is_string($data)) {
|
||||
$data = json_decode($data);
|
||||
}
|
||||
|
||||
if(! is_object($data))
|
||||
return '';
|
||||
return $ret;
|
||||
|
||||
jsonld_set_document_loader('jsonld_document_loader');
|
||||
|
||||
|
||||
try {
|
||||
$d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
|
||||
$ret = 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));
|
||||
}
|
||||
|
||||
return $d;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
static function salmon_sign($data,$channel) {
|
||||
@@ -116,7 +118,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'],
|
||||
|
||||
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;
|
||||
@@ -142,8 +145,8 @@ class Libzotdir {
|
||||
if(! $directory_sort_order)
|
||||
$directory_sort_order = 'date';
|
||||
|
||||
$current_order = (($_REQUEST['order']) ? $_REQUEST['order'] : $directory_sort_order);
|
||||
$suggest = (($_REQUEST['suggest']) ? '&suggest=' . $_REQUEST['suggest'] : '');
|
||||
$current_order = $_REQUEST['order'] ?? $directory_sort_order;
|
||||
$suggest = ((isset($_REQUEST['suggest'])) ? '&suggest=' . $_REQUEST['suggest'] : '');
|
||||
|
||||
$url = 'directory?f=';
|
||||
|
||||
@@ -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();
|
||||
@@ -435,22 +453,29 @@ class Libzotdir {
|
||||
if (! $hash)
|
||||
return false;
|
||||
|
||||
$arr = array();
|
||||
$arr = [];
|
||||
|
||||
$arr['xprof_hash'] = $hash;
|
||||
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('','',$profile['birthday'],'Y-m-d')); // !!!! check this for 0000 year
|
||||
$arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0);
|
||||
$arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_gender'] = (($profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_marital'] = (($profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_sexual'] = (($profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_locale'] = (($profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_region'] = (($profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_postcode'] = (($profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_country'] = (($profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_about'] = (($profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_homepage'] = (($profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_hometown'] = (($profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_hash'] = $hash;
|
||||
$arr['xprof_dob'] = '0000-00-00';
|
||||
|
||||
if (isset($profile['birthday'])) {
|
||||
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00')
|
||||
? $profile['birthday']
|
||||
: datetime_convert('', '', $profile['birthday'], 'Y-m-d')); // !!!! check this for 0000 year
|
||||
}
|
||||
|
||||
$arr['xprof_age'] = ((isset($profile['age']) && $profile['age']) ? intval($profile['age']) : 0);
|
||||
$arr['xprof_desc'] = ((isset($profile['description']) && $profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_gender'] = ((isset($profile['gender']) && $profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_marital'] = ((isset($profile['marital']) && $profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_sexual'] = ((isset($profile['sexual']) && $profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_locale'] = ((isset($profile['locale']) && $profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_region'] = ((isset($profile['region']) && $profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_postcode'] = ((isset($profile['postcode']) && $profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_country'] = ((isset($profile['country']) && $profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_about'] = ((isset($profile['about']) && $profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_homepage'] = ((isset($profile['homepage']) && $profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
$arr['xprof_hometown'] = ((isset($profile['hometown']) && $profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : '');
|
||||
|
||||
$clean = array();
|
||||
if (array_key_exists('keywords', $profile) and is_array($profile['keywords'])) {
|
||||
@@ -625,8 +650,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 +665,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 +676,4 @@ class Libzotdir {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,87 +2,120 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
class MessageFilter {
|
||||
|
||||
public static function evaluate($item, $incl, $excl) {
|
||||
|
||||
static public function evaluate($item,$incl,$excl) {
|
||||
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
unobscure($item);
|
||||
|
||||
$text = prepare_text($item['body'],$item['mimetype']);
|
||||
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
|
||||
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
|
||||
|
||||
|
||||
$lang = null;
|
||||
|
||||
if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false) || (strpos($incl,'lang!=') !== false) || (strpos($excl,'lang!=') !== false)) {
|
||||
if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) {
|
||||
$lang = detect_language($text);
|
||||
}
|
||||
|
||||
$tags = ((is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
|
||||
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
|
||||
|
||||
// exclude always has priority
|
||||
|
||||
$exclude = (($excl) ? explode("\n",$excl) : null);
|
||||
$exclude = (($excl) ? explode("\n", $excl) : null);
|
||||
|
||||
if($exclude) {
|
||||
foreach($exclude as $word) {
|
||||
if ($exclude) {
|
||||
foreach ($exclude as $word) {
|
||||
$word = trim($word);
|
||||
if(! $word)
|
||||
if (! $word) {
|
||||
continue;
|
||||
if(substr($word,0,1) === '#' && $tags) {
|
||||
foreach($tags as $t)
|
||||
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
return false;
|
||||
}
|
||||
elseif(substr($word,0,1) === '$' && $tags) {
|
||||
foreach($tags as $t)
|
||||
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
return false;
|
||||
if (isset($lang) && ((strpos($word, 'lang=') === 0) || (strpos($word, 'lang!=') === 0))) {
|
||||
if (!strlen($lang)) {
|
||||
// Result is ambiguous. As we are matching deny rules only at this time, continue tests.
|
||||
// Any matching deny rule concludes testing.
|
||||
continue;
|
||||
}
|
||||
if (strpos($word, 'lang=') === 0 && strcasecmp($lang, trim(substr($word, 5))) == 0) {
|
||||
return false;
|
||||
} elseif (strpos($word, 'lang!=') === 0 && strcasecmp($lang, trim(substr($word, 6))) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} elseif (substr($word, 0, 1) === '$' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} elseif (substr($word, 0, 2) === '?+') {
|
||||
if (self::test_condition(substr($word, 2), $item['obj'])) {
|
||||
return false;
|
||||
}
|
||||
} elseif (substr($word, 0, 1) === '?') {
|
||||
if (self::test_condition(substr($word, 1), $item)) {
|
||||
return false;
|
||||
}
|
||||
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
|
||||
return false;
|
||||
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
|
||||
return false;
|
||||
elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0))
|
||||
return false;
|
||||
elseif(stristr($text,$word) !== false)
|
||||
} elseif (stristr($text, $word) !== false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$include = (($incl) ? explode("\n",$incl) : null);
|
||||
$include = (($incl) ? explode("\n", $incl) : null);
|
||||
|
||||
if($include) {
|
||||
foreach($include as $word) {
|
||||
if ($include) {
|
||||
foreach ($include as $word) {
|
||||
$word = trim($word);
|
||||
if(! $word)
|
||||
if (! $word) {
|
||||
continue;
|
||||
if(substr($word,0,1) === '#' && $tags) {
|
||||
foreach($tags as $t)
|
||||
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
return true;
|
||||
}
|
||||
elseif(substr($word,0,1) === '$' && $tags) {
|
||||
foreach($tags as $t)
|
||||
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
|
||||
return true;
|
||||
if (isset($lang) && ((strpos($word, 'lang=') === 0) || (strpos($word, 'lang!=') === 0))) {
|
||||
if (!strlen($lang)) {
|
||||
// Result is ambiguous. However we are checking allow rules
|
||||
// and an ambiguous language is always permitted.
|
||||
return true;
|
||||
}
|
||||
if (strpos($word, 'lang=') === 0 && strcasecmp($lang, trim(substr($word, 5))) == 0) {
|
||||
return true;
|
||||
} elseif (strpos($word, 'lang!=') === 0 && strcasecmp($lang, trim(substr($word, 6))) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
|
||||
elseif (substr($word, 0, 1) === '#' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} elseif (substr($word, 0, 1) === '$' && $tags) {
|
||||
foreach ($tags as $t) {
|
||||
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} elseif (substr($word, 0, 2) === '?+') {
|
||||
if (self::test_condition(substr($word, 2), $item['obj'])) {
|
||||
return true;
|
||||
}
|
||||
} elseif (substr($word, 0, 1) === '?') {
|
||||
if (self::test_condition(substr($word, 1), $item)) {
|
||||
return true;
|
||||
}
|
||||
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
|
||||
return true;
|
||||
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
|
||||
return true;
|
||||
elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0))
|
||||
return true;
|
||||
elseif(stristr($text,$word) !== false)
|
||||
} elseif (stristr($text, $word) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -90,4 +123,123 @@ class MessageFilter {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Test for Conditional Execution conditions. Shamelessly ripped off from Code/Render/Comanche
|
||||
*
|
||||
* This is extensible. The first version of variable testing supports tests of the forms:
|
||||
*
|
||||
* - ?foo ~= baz which will check if item.foo contains the string 'baz';
|
||||
* - ?foo == baz which will check if item.foo is the string 'baz';
|
||||
* - ?foo != baz which will check if item.foo is not the string 'baz';
|
||||
* - ?foo >= 3 which will check if item.foo is greater than or equal to 3;
|
||||
* - ?foo > 3 which will check if item.foo is greater than 3;
|
||||
* - ?foo <= 3 which will check if item.foo is less than or equal to 3;
|
||||
* - ?foo < 3 which will check if item.foo is less than 3;
|
||||
*
|
||||
* - ?foo {} baz which will check if 'baz' is an array element in item.foo
|
||||
* - ?foo {*} baz which will check if 'baz' is an array key in item.foo
|
||||
* - ?foo which will check for a return of a true condition for item.foo;
|
||||
* - ?!foo which will check for a return of a false condition for item.foo;
|
||||
*
|
||||
* The values 0, '', an empty array, and an unset value will all evaluate to false.
|
||||
*
|
||||
* @param string $s
|
||||
* @param array $item
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
public static function test_condition($s,$item) {
|
||||
|
||||
if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (stripos($x, trim($matches[2])) !== false) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x == trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\!\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x != trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\>\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x >= trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\<\=\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x <= trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x > trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x < trim($matches[2])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (is_array($x) && in_array(trim($matches[2]), $x)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (is_array($x) && array_key_exists(trim($matches[2]), $x)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ordering of this check (for falsiness) with relation to the following one (check for truthiness) is important.
|
||||
if (preg_match('/\!(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if (!$x) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/(.*?)$/', $s, $matches)) {
|
||||
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
|
||||
if ($x) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
define ( 'NWIKI_ITEM_RESOURCE_TYPE', 'nwiki' );
|
||||
|
||||
class NativeWiki {
|
||||
|
||||
|
||||
static public function listwikis($channel, $observer_hash) {
|
||||
|
||||
$sql_extra = item_permissions_sql($channel['channel_id'], $observer_hash);
|
||||
$wikis = q("SELECT * FROM item
|
||||
WHERE resource_type = '%s' AND mid = parent_mid AND uid = %d AND item_deleted = 0 $sql_extra",
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
if($wikis) {
|
||||
foreach($wikis as &$w) {
|
||||
|
||||
$w['json_allow_cid'] = acl2json($w['allow_cid']);
|
||||
$w['json_allow_gid'] = acl2json($w['allow_gid']);
|
||||
$w['json_deny_cid'] = acl2json($w['deny_cid']);
|
||||
$w['json_deny_gid'] = acl2json($w['deny_gid']);
|
||||
|
||||
$w['rawName'] = get_iconfig($w, 'wiki', 'rawName');
|
||||
$w['htmlName'] = escape_tags($w['rawName']);
|
||||
//$w['urlName'] = urlencode(urlencode($w['rawName']));
|
||||
$w['urlName'] = self::name_encode($w['rawName']);
|
||||
$w['mimeType'] = get_iconfig($w, 'wiki', 'mimeType');
|
||||
$w['typelock'] = get_iconfig($w, 'wiki', 'typelock');
|
||||
$w['lockstate'] = (($w['allow_cid'] || $w['allow_gid'] || $w['deny_cid'] || $w['deny_gid']) ? 'lock' : 'unlock');
|
||||
}
|
||||
}
|
||||
// TODO: query db for wikis the observer can access. Return with two lists, for read and write access
|
||||
return array('wikis' => $wikis);
|
||||
}
|
||||
|
||||
|
||||
function create_wiki($channel, $observer_hash, $wiki, $acl) {
|
||||
|
||||
$resource_id = new_uuid();
|
||||
$uuid = new_uuid();
|
||||
|
||||
$ac = $acl->get();
|
||||
$mid = z_root() . '/item/' . $uuid;
|
||||
|
||||
$arr = array(); // Initialize the array of parameters for the post
|
||||
$item_hidden = ((intval($wiki['postVisible']) === 0) ? 1 : 0);
|
||||
$wiki_url = z_root() . '/wiki/' . $channel['channel_address'] . '/' . $wiki['urlName'];
|
||||
$arr['aid'] = $channel['channel_account_id'];
|
||||
$arr['uuid'] = $uuid;
|
||||
$arr['uid'] = $channel['channel_id'];
|
||||
$arr['mid'] = $mid;
|
||||
$arr['parent_mid'] = $mid;
|
||||
$arr['item_hidden'] = $item_hidden;
|
||||
$arr['resource_type'] = NWIKI_ITEM_RESOURCE_TYPE;
|
||||
$arr['resource_id'] = $resource_id;
|
||||
$arr['owner_xchan'] = $channel['channel_hash'];
|
||||
$arr['author_xchan'] = $observer_hash;
|
||||
$arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']);
|
||||
$arr['llink'] = $arr['plink'];
|
||||
$arr['title'] = $wiki['htmlName']; // name of new wiki;
|
||||
$arr['allow_cid'] = $ac['allow_cid'];
|
||||
$arr['allow_gid'] = $ac['allow_gid'];
|
||||
$arr['deny_cid'] = $ac['deny_cid'];
|
||||
$arr['deny_gid'] = $ac['deny_gid'];
|
||||
$arr['item_wall'] = 1;
|
||||
$arr['item_origin'] = 1;
|
||||
$arr['item_thread_top'] = 1;
|
||||
$arr['item_private'] = intval($acl->is_private());
|
||||
$arr['verb'] = ACTIVITY_CREATE;
|
||||
$arr['obj_type'] = ACTIVITY_OBJ_WIKI;
|
||||
$arr['body'] = '[table][tr][td][h1]New Wiki[/h1][/td][/tr][tr][td][zrl=' . $wiki_url . ']' . $wiki['htmlName'] . '[/zrl][/td][/tr][/table]';
|
||||
|
||||
$arr['public_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_wiki'),true);
|
||||
|
||||
// Save the wiki name information using iconfig. This is shareable.
|
||||
if(! set_iconfig($arr, 'wiki', 'rawName', $wiki['rawName'], true)) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
if(! set_iconfig($arr, 'wiki', 'mimeType', $wiki['mimeType'], true)) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
|
||||
set_iconfig($arr,'wiki','typelock',$wiki['typelock'],true);
|
||||
|
||||
$post = item_store($arr);
|
||||
|
||||
$item_id = $post['item_id'];
|
||||
|
||||
if($item_id) {
|
||||
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'activity', $item_id));
|
||||
return array('item' => $post['item'], 'item_id' => $item_id, 'success' => true);
|
||||
}
|
||||
else {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
}
|
||||
|
||||
function update_wiki($channel_id, $observer_hash, $arr, $acl) {
|
||||
|
||||
$w = self::get_wiki($channel_id, $observer_hash, $arr['resource_id']);
|
||||
$item = $w['wiki'];
|
||||
|
||||
if(! $item) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
|
||||
$x = $acl->get();
|
||||
|
||||
$item['allow_cid'] = $x['allow_cid'];
|
||||
$item['allow_gid'] = $x['allow_gid'];
|
||||
$item['deny_cid'] = $x['deny_cid'];
|
||||
$item['deny_gid'] = $x['deny_gid'];
|
||||
$item['item_private'] = intval($acl->is_private());
|
||||
|
||||
$update_title = false;
|
||||
|
||||
if($item['title'] !== $arr['updateRawName']) {
|
||||
$update_title = true;
|
||||
$item['title'] = $arr['updateRawName'];
|
||||
}
|
||||
|
||||
$update = item_store_update($item);
|
||||
|
||||
$item_id = $update['item_id'];
|
||||
|
||||
// update acl for any existing wiki pages
|
||||
|
||||
q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d where resource_type = 'nwikipage' and resource_id = '%s'",
|
||||
dbesc($item['allow_cid']),
|
||||
dbesc($item['allow_gid']),
|
||||
dbesc($item['deny_cid']),
|
||||
dbesc($item['deny_gid']),
|
||||
dbesc($item['item_private']),
|
||||
dbesc($arr['resource_id'])
|
||||
);
|
||||
|
||||
|
||||
if($update['item_id']) {
|
||||
info( t('Wiki updated successfully'));
|
||||
if($update_title) {
|
||||
// Update the wiki name information using iconfig.
|
||||
if(! set_iconfig($update['item_id'], 'wiki', 'rawName', $arr['updateRawName'], true)) {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
}
|
||||
return array('item' => $update['item'], 'item_id' => $update['item_id'], 'success' => $update['success']);
|
||||
}
|
||||
else {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
}
|
||||
|
||||
static public function sync_a_wiki_item($uid,$id,$resource_id) {
|
||||
|
||||
|
||||
$r = q("SELECT * from item WHERE uid = %d AND ( id = %d OR ( resource_type = '%s' and resource_id = '%s' )) ",
|
||||
intval($uid),
|
||||
intval($id),
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
$q = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s'",
|
||||
dbesc($r[0]['resource_id'])
|
||||
);
|
||||
if($q) {
|
||||
$r = array_merge($r,$q);
|
||||
}
|
||||
xchan_query($r);
|
||||
$sync_item = fetch_post_tags($r);
|
||||
if($sync_item) {
|
||||
$pkt = [];
|
||||
foreach($sync_item as $w) {
|
||||
$pkt[] = encode_item($w,true);
|
||||
}
|
||||
build_sync_packet($uid,array('wiki' => $pkt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
info( t('Wiki files deleted successfully'));
|
||||
|
||||
return array('item' => $item, 'item_id' => $item['id'], 'success' => (($drop === 1) ? true : false));
|
||||
}
|
||||
|
||||
|
||||
static public 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",
|
||||
intval($channel_id),
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
if(! $item) {
|
||||
return array('wiki' => null);
|
||||
}
|
||||
else {
|
||||
|
||||
$w = $item[0]; // wiki item table record
|
||||
// Get wiki metadata
|
||||
$rawName = get_iconfig($w, 'wiki', 'rawName');
|
||||
$mimeType = get_iconfig($w, 'wiki', 'mimeType');
|
||||
$typelock = get_iconfig($w, 'wiki', 'typelock');
|
||||
|
||||
return array(
|
||||
'wiki' => $w,
|
||||
'rawName' => $rawName,
|
||||
'htmlName' => escape_tags($rawName),
|
||||
//'urlName' => urlencode(urlencode($rawName)),
|
||||
'urlName' => self::name_encode($rawName),
|
||||
'mimeType' => $mimeType,
|
||||
'typelock' => $typelock
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public function exists_by_name($uid, $urlName) {
|
||||
|
||||
$sql_extra = item_permissions_sql($uid);
|
||||
|
||||
$item = q("SELECT item.id, resource_id FROM item left join iconfig on iconfig.iid = item.id
|
||||
WHERE resource_type = '%s' AND iconfig.v = '%s' AND uid = %d
|
||||
AND item_deleted = 0 $sql_extra limit 1",
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
//dbesc(urldecode($urlName)),
|
||||
dbesc(self::name_decode($urlName)),
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
if($item) {
|
||||
return array('id' => $item[0]['id'], 'resource_id' => $item[0]['resource_id']);
|
||||
}
|
||||
else {
|
||||
return array('id' => null, 'resource_id' => null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public function get_permissions($resource_id, $owner_id, $observer_hash) {
|
||||
// TODO: For now, only the owner can edit
|
||||
$sql_extra = item_permissions_sql($owner_id, $observer_hash);
|
||||
|
||||
if(local_channel() && local_channel() == $owner_id) {
|
||||
return [ 'read' => true, 'write' => true, 'success' => true ];
|
||||
}
|
||||
|
||||
$r = q("SELECT * FROM item WHERE uid = %d and resource_type = '%s' AND resource_id = '%s' $sql_extra LIMIT 1",
|
||||
intval($owner_id),
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
return array('read' => false, 'write' => false, 'success' => true);
|
||||
}
|
||||
else {
|
||||
// TODO: Create a new permission setting for wiki analogous to webpages. Until
|
||||
// then, use webpage permissions
|
||||
$write = perm_is_allowed($owner_id, $observer_hash,'write_wiki');
|
||||
return array('read' => true, 'write' => $write, 'success' => true);
|
||||
}
|
||||
}
|
||||
|
||||
public static function name_encode ($string) {
|
||||
|
||||
$string = html_entity_decode($string);
|
||||
$encoding = mb_internal_encoding();
|
||||
mb_internal_encoding("UTF-8");
|
||||
$ret = mb_ereg_replace_callback ('[^A-Za-z0-9\-\_\.\~]',function ($char) {
|
||||
$charhex = unpack('H*',$char[0]);
|
||||
$ret = '('.$charhex[1].')';
|
||||
return $ret;
|
||||
}
|
||||
,$string);
|
||||
mb_internal_encoding($encoding);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function name_decode ($string) {
|
||||
|
||||
$encoding = mb_internal_encoding();
|
||||
mb_internal_encoding("UTF-8");
|
||||
$ret = mb_ereg_replace_callback ('(\(([0-9a-f]+)\))',function ($chars) {
|
||||
return pack('H*',$chars[2]);
|
||||
}
|
||||
,$string);
|
||||
mb_internal_encoding($encoding);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,701 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use \Zotlabs\Lib as Zlib;
|
||||
|
||||
class NativeWikiPage {
|
||||
|
||||
static public function page_list($channel_id,$observer_hash, $resource_id) {
|
||||
|
||||
// TODO: Create item table records for pages so that metadata like title can be applied
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id,$observer_hash,$resource_id);
|
||||
|
||||
$pages[] = [
|
||||
'resource_id' => '',
|
||||
'title' => 'Home',
|
||||
'url' => 'Home',
|
||||
'link_id' => 'id_wiki_home_0'
|
||||
];
|
||||
|
||||
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
|
||||
|
||||
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and item_deleted = 0
|
||||
$sql_extra order by title asc",
|
||||
dbesc($resource_id),
|
||||
intval($channel_id)
|
||||
);
|
||||
if($r) {
|
||||
$x = [];
|
||||
$y = [];
|
||||
|
||||
foreach($r as $rv) {
|
||||
if(! in_array($rv['mid'],$x)) {
|
||||
$y[] = $rv;
|
||||
$x[] = $rv['mid'];
|
||||
}
|
||||
}
|
||||
|
||||
$items = fetch_post_tags($y,true);
|
||||
|
||||
foreach($items as $page_item) {
|
||||
$title = get_iconfig($page_item['id'],'nwikipage','pagetitle',t('(No Title)'));
|
||||
if(urldecode($title) !== 'Home') {
|
||||
$pages[] = [
|
||||
'resource_id' => $resource_id,
|
||||
'title' => escape_tags($title),
|
||||
//'url' => str_replace('%2F','/',urlencode(str_replace('%2F','/',urlencode($title)))),
|
||||
'url' => Zlib\NativeWiki::name_encode($title),
|
||||
'link_id' => 'id_' . substr($resource_id, 0, 10) . '_' . $page_item['id']
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array('pages' => $pages, 'wiki' => $w);
|
||||
}
|
||||
|
||||
|
||||
static public function create_page($channel_id, $observer_hash, $name, $resource_id, $mimetype = 'text/bbcode') {
|
||||
|
||||
logger('mimetype: ' . $mimetype);
|
||||
|
||||
if(! in_array($mimetype,[ 'text/markdown','text/bbcode','text/plain','text/html' ]))
|
||||
$mimetype = 'text/markdown';
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if (! $w['wiki']) {
|
||||
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
|
||||
}
|
||||
|
||||
// backslashes won't work well in the javascript functions
|
||||
$name = str_replace('\\','',$name);
|
||||
|
||||
// create an empty activity
|
||||
|
||||
$arr = [];
|
||||
$arr['uid'] = $channel_id;
|
||||
$arr['author_xchan'] = $observer_hash;
|
||||
$arr['mimetype'] = $mimetype;
|
||||
$arr['title'] = $name;
|
||||
$arr['resource_type'] = 'nwikipage';
|
||||
$arr['resource_id'] = $resource_id;
|
||||
$arr['allow_cid'] = $w['wiki']['allow_cid'];
|
||||
$arr['allow_gid'] = $w['wiki']['allow_gid'];
|
||||
$arr['deny_cid'] = $w['wiki']['deny_cid'];
|
||||
$arr['deny_gid'] = $w['wiki']['deny_gid'];
|
||||
|
||||
$arr['public_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel_id,'view_wiki'),true);
|
||||
|
||||
// We may wish to change this some day.
|
||||
$arr['item_unpublished'] = 1;
|
||||
|
||||
set_iconfig($arr,'nwikipage','pagetitle',(($name) ? $name : t('(No Title)')),true);
|
||||
|
||||
$p = post_activity_item($arr, false, false);
|
||||
|
||||
if($p['item_id']) {
|
||||
$page = [
|
||||
'rawName' => $name,
|
||||
'htmlName' => escape_tags($name),
|
||||
//'urlName' => urlencode($name),
|
||||
'urlName' => Zlib\NativeWiki::name_encode($name)
|
||||
|
||||
];
|
||||
|
||||
return array('page' => $page, 'item_id' => $p['item_id'], 'item' => $p['activity'], 'wiki' => $w, 'message' => '', 'success' => true);
|
||||
}
|
||||
return [ 'success' => false, 'message' => t('Wiki page create failed.') ];
|
||||
}
|
||||
|
||||
static public function rename_page($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$pageNewName = ((array_key_exists('pageNewName',$arr)) ? $arr['pageNewName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if(! $w['wiki']) {
|
||||
return array('message' => t('Wiki not found.'), 'success' => false);
|
||||
}
|
||||
|
||||
|
||||
$ic = q("select * from iconfig left join item on iconfig.iid = item.id
|
||||
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageNewName)
|
||||
);
|
||||
|
||||
if($ic) {
|
||||
return [ 'success' => false, 'message' => t('Destination name already exists') ];
|
||||
}
|
||||
|
||||
|
||||
$ids = [];
|
||||
|
||||
$ic = q("select *, item.id as item_id from iconfig left join item on iconfig.iid = item.id
|
||||
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageUrlName)
|
||||
);
|
||||
|
||||
if($ic) {
|
||||
foreach($ic as $c) {
|
||||
set_iconfig($c['item_id'],'nwikipage','pagetitle',$pageNewName);
|
||||
$ids[] = $c['item_id'];
|
||||
}
|
||||
|
||||
$str_ids = implode(',', $ids);
|
||||
q("update item set title = '%s' where id in ($str_ids)",
|
||||
dbesc($pageNewName)
|
||||
);
|
||||
|
||||
$page = [
|
||||
'rawName' => $pageNewName,
|
||||
'htmlName' => escape_tags($pageNewName),
|
||||
//'urlName' => urlencode(escape_tags($pageNewName))
|
||||
'urlName' => Zlib\NativeWiki::name_encode($pageNewName)
|
||||
];
|
||||
|
||||
return [ 'success' => true, 'page' => $page ];
|
||||
}
|
||||
|
||||
return [ 'success' => false, 'item_id' => $c['item_id'], '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'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? intval($arr['channel_id']) : 0);
|
||||
$revision = ((array_key_exists('revision',$arr)) ? intval($arr['revision']) : (-1));
|
||||
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (! $w['wiki']) {
|
||||
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
|
||||
}
|
||||
|
||||
$item = self::load_page($arr);
|
||||
|
||||
if($item) {
|
||||
$content = $item['body'];
|
||||
|
||||
return [
|
||||
'content' => $content,
|
||||
'mimeType' => $w['mimeType'],
|
||||
'pageMimeType' => $item['mimetype'],
|
||||
'message' => '',
|
||||
'success' => true
|
||||
];
|
||||
}
|
||||
|
||||
return array('content' => null, 'message' => t('Error reading page content'), 'success' => false);
|
||||
|
||||
}
|
||||
|
||||
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'] : '');
|
||||
$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 array('history' => null, 'message' => 'Error reading wiki', 'success' => false);
|
||||
}
|
||||
|
||||
$items = self::load_page_history($arr);
|
||||
|
||||
$history = [];
|
||||
|
||||
if($items) {
|
||||
$processed = 0;
|
||||
foreach($items as $item) {
|
||||
if($processed > 1000)
|
||||
break;
|
||||
$processed ++;
|
||||
$history[] = [
|
||||
'revision' => $item['revision'],
|
||||
'date' => datetime_convert('UTC',date_default_timezone_get(),$item['edited']),
|
||||
'name' => $item['author']['xchan_name'],
|
||||
'title' => get_iconfig($item,'nwikipage','commit_msg')
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
return [ 'success' => true, 'history' => $history ];
|
||||
}
|
||||
|
||||
return [ 'success' => false ];
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function load_page($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
$revision = ((array_key_exists('revision',$arr)) ? $arr['revision'] : (-1));
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if (! $w['wiki']) {
|
||||
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
|
||||
}
|
||||
|
||||
$ids = '';
|
||||
|
||||
$ic = q("select * from iconfig left join item on iconfig.iid = item.id where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageUrlName)
|
||||
);
|
||||
|
||||
if($ic) {
|
||||
foreach($ic as $c) {
|
||||
if($ids)
|
||||
$ids .= ',';
|
||||
$ids .= intval($c['iid']);
|
||||
}
|
||||
}
|
||||
|
||||
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
|
||||
|
||||
if($revision == (-1))
|
||||
$sql_extra .= " order by revision desc ";
|
||||
elseif($revision)
|
||||
$sql_extra .= " and revision = " . intval($revision) . " ";
|
||||
|
||||
$r = null;
|
||||
|
||||
|
||||
if($ids) {
|
||||
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and id in ( $ids ) $sql_extra limit 1",
|
||||
dbesc($resource_id),
|
||||
intval($channel_id)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
$items = fetch_post_tags($r,true);
|
||||
return $items[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static public function load_page_history($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
$revision = ((array_key_exists('revision',$arr)) ? $arr['revision'] : (-1));
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (! $w['wiki']) {
|
||||
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
|
||||
}
|
||||
|
||||
$ids = '';
|
||||
|
||||
$ic = q("select * from iconfig left join item on iconfig.iid = item.id where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageUrlName)
|
||||
);
|
||||
|
||||
if($ic) {
|
||||
foreach($ic as $c) {
|
||||
if($ids)
|
||||
$ids .= ',';
|
||||
$ids .= intval($c['iid']);
|
||||
}
|
||||
}
|
||||
|
||||
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
|
||||
|
||||
$sql_extra .= " order by revision desc ";
|
||||
|
||||
$r = null;
|
||||
if($ids) {
|
||||
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and id in ( $ids ) and item_deleted = 0 $sql_extra",
|
||||
dbesc($resource_id),
|
||||
intval($channel_id)
|
||||
);
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r,true);
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static public function save_page($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
|
||||
$content = ((array_key_exists('content',$arr)) ? $arr['content'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
$revision = ((array_key_exists('revision',$arr)) ? $arr['revision'] : 0);
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if (!$w['wiki']) {
|
||||
return array('message' => t('Error reading wiki'), 'success' => false);
|
||||
}
|
||||
|
||||
|
||||
// fetch the most recently saved revision.
|
||||
|
||||
$item = self::load_page($arr);
|
||||
|
||||
if(! $item) {
|
||||
return array('message' => t('Page not found'), 'success' => false);
|
||||
}
|
||||
|
||||
$mimetype = $item['mimetype'];
|
||||
|
||||
// change just the fields we need to change to create a revision;
|
||||
|
||||
unset($item['id']);
|
||||
unset($item['author']);
|
||||
$item['parent'] = 0;
|
||||
$item['body'] = $content;
|
||||
$item['author_xchan'] = $observer_hash;
|
||||
$item['revision'] = (($arr['revision']) ? intval($arr['revision']) + 1 : intval($item['revision']) + 1);
|
||||
$item['edited'] = datetime_convert();
|
||||
$item['mimetype'] = $mimetype;
|
||||
|
||||
if($item['iconfig'] && is_array($item['iconfig']) && count($item['iconfig'])) {
|
||||
for($x = 0; $x < count($item['iconfig']); $x ++) {
|
||||
unset($item['iconfig'][$x]['id']);
|
||||
unset($item['iconfig'][$x]['iid']);
|
||||
}
|
||||
}
|
||||
|
||||
$ret = item_store($item, false, false);
|
||||
|
||||
if($ret['item_id'])
|
||||
return array('message' => '', 'item_id' => $ret['item_id'], 'filename' => $filename, '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);
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if(! $w['wiki']) {
|
||||
return [ 'success' => false, 'message' => t('Error reading wiki') ];
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
|
||||
$ic = q("select * from iconfig left join item on iconfig.iid = item.id
|
||||
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
|
||||
intval($channel_id),
|
||||
dbesc($pageUrlName)
|
||||
);
|
||||
|
||||
if($ic) {
|
||||
foreach($ic as $c) {
|
||||
$ids[] = intval($c['iid']);
|
||||
}
|
||||
}
|
||||
|
||||
if($ids) {
|
||||
drop_items($ids);
|
||||
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);
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
if (! $commitHash) {
|
||||
return array('content' => $content, '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);
|
||||
}
|
||||
|
||||
$x = $arr;
|
||||
|
||||
if(intval($commitHash) > 0) {
|
||||
unset($x['commitHash']);
|
||||
$x['revision'] = intval($commitHash) - 1;
|
||||
$loaded = self::load_page($x);
|
||||
|
||||
if($loaded) {
|
||||
$content = $loaded['body'];
|
||||
return [ 'content' => $content, 'success' => true ];
|
||||
}
|
||||
return [ 'content' => $content, '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));
|
||||
$compareCommit = ((array_key_exists('compareCommit',$arr)) ? $arr['compareCommit'] : 0);
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
|
||||
if (!$w['wiki']) {
|
||||
return array('message' => t('Error reading wiki'), 'success' => false);
|
||||
}
|
||||
|
||||
$x = $arr;
|
||||
$x['revision'] = (-1);
|
||||
|
||||
$currpage = self::load_page($x);
|
||||
if($currpage)
|
||||
$currentContent = $currpage['body'];
|
||||
|
||||
$x['revision'] = $compareCommit;
|
||||
$comppage = self::load_page($x);
|
||||
if($comppage)
|
||||
$compareContent = $comppage['body'];
|
||||
|
||||
if($currpage && $comppage) {
|
||||
require_once('library/class.Diff.php');
|
||||
$diff = \Diff::toTable(\Diff::compare($currentContent, $compareContent));
|
||||
|
||||
return [ 'success' => true, 'diff' => $diff ];
|
||||
}
|
||||
return [ 'success' => false, 'message' => t('Compare: object not found.') ];
|
||||
|
||||
}
|
||||
|
||||
static public function commit($arr) {
|
||||
|
||||
$commit_msg = ((array_key_exists('commit_msg', $arr)) ? $arr['commit_msg'] : t('Page updated'));
|
||||
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
|
||||
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
|
||||
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : t('Untitled'));
|
||||
|
||||
if(array_key_exists('resource_id', $arr)) {
|
||||
$resource_id = $arr['resource_id'];
|
||||
}
|
||||
else {
|
||||
return array('message' => t('Wiki resource_id required for git commit'), 'success' => false);
|
||||
}
|
||||
|
||||
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
|
||||
if (! $w['wiki']) {
|
||||
return array('message' => t('Error reading wiki'), 'success' => false);
|
||||
}
|
||||
|
||||
|
||||
$page = self::load_page($arr);
|
||||
|
||||
if($page) {
|
||||
set_iconfig($page['id'],'nwikipage','commit_msg',escape_tags($commit_msg),true);
|
||||
return [ 'success' => true, 'item_id' => $page['id'], 'page' => $page ];
|
||||
}
|
||||
|
||||
return [ 'success' => false, 'message' => t('Page not found.') ];
|
||||
|
||||
}
|
||||
|
||||
static public function convert_links($s, $wikiURL) {
|
||||
|
||||
if (strpos($s,'[[') !== false) {
|
||||
preg_match_all("/\[\[(.*?)\]\]/", $s, $match);
|
||||
$pages = $pageURLs = array();
|
||||
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;
|
||||
}
|
||||
$idx = 0;
|
||||
while(strpos($s,'[[') !== false) {
|
||||
$replace = '<a href="'.$wikiURL.'/'.$pageURLs[$idx].'">'.$pages[$idx].'</a>';
|
||||
$s = preg_replace("/\[\[(.*?)\]\]/", $replace, $s, 1);
|
||||
$idx++;
|
||||
}
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
static public function render_page_history($arr) {
|
||||
|
||||
$pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
|
||||
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
|
||||
|
||||
$pageHistory = self::page_history([
|
||||
'channel_id' => \App::$profile_uid,
|
||||
'observer_hash' => get_observer_hash(),
|
||||
'resource_id' => $resource_id,
|
||||
'pageUrlName' => $pageUrlName
|
||||
]);
|
||||
|
||||
return replace_macros(get_markup_template('nwiki_page_history.tpl'), array(
|
||||
'$pageHistory' => $pageHistory['history'],
|
||||
'$permsWrite' => $arr['permsWrite'],
|
||||
'$name_lbl' => t('Name'),
|
||||
'$msg_label' => t('Message','wiki_history'),
|
||||
'$date_lbl' => t('Date'),
|
||||
'$revert_btn' => t('Revert'),
|
||||
'$compare_btn' => t('Compare')
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Replace the instances of the string [toc] with a list element that will be populated by
|
||||
* a table of contents by the JavaScript library
|
||||
* @param string $s
|
||||
* @return string
|
||||
*/
|
||||
static public function generate_toc($s) {
|
||||
if (strpos($s,'[toc]') !== false) {
|
||||
//$toc_md = wiki_toc($s); // Generate Markdown-formatted list prior to HTML render
|
||||
$toc_md = '<ul id="wiki-toc"></ul>'; // use the available jQuery plugin http://ndabas.github.io/toc/
|
||||
$s = preg_replace("/\[toc\]/", $toc_md, $s, -1);
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a select set of bbcode tags. Much of the code is copied from include/bbcode.php
|
||||
* @param string $s
|
||||
* @return string
|
||||
*/
|
||||
static public function bbcode($s) {
|
||||
|
||||
$s = str_replace(array('[baseurl]', '[sitename]'), array(z_root(), get_config('system', 'sitename')), $s);
|
||||
|
||||
$s = preg_replace_callback("/\[observer\.language\=(.*?)\](.*?)\[\/observer\]/ism",'oblanguage_callback', $s);
|
||||
|
||||
$s = preg_replace_callback("/\[observer\.language\!\=(.*?)\](.*?)\[\/observer\]/ism",'oblanguage_necallback', $s);
|
||||
|
||||
|
||||
$observer = \App::get_observer();
|
||||
if ($observer) {
|
||||
$s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">';
|
||||
$s2 = '</span>';
|
||||
$obsBaseURL = $observer['xchan_connurl'];
|
||||
$obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
|
||||
$s = str_replace('[observer.baseurl]', $obsBaseURL, $s);
|
||||
$s = str_replace('[observer.url]', $observer['xchan_url'], $s);
|
||||
$s = str_replace('[observer.name]', $s1 . $observer['xchan_name'] . $s2, $s);
|
||||
$s = str_replace('[observer.address]', $s1 . $observer['xchan_addr'] . $s2, $s);
|
||||
$s = str_replace('[observer.webname]', substr($observer['xchan_addr'], 0, strpos($observer['xchan_addr'], '@')), $s);
|
||||
$s = str_replace('[observer.photo]', '', $s);
|
||||
}
|
||||
else {
|
||||
$s = str_replace('[observer.baseurl]', '', $s);
|
||||
$s = str_replace('[observer.url]', '', $s);
|
||||
$s = str_replace('[observer.name]', '', $s);
|
||||
$s = str_replace('[observer.address]', '', $s);
|
||||
$s = str_replace('[observer.webname]', '', $s);
|
||||
$s = str_replace('[observer.photo]', '', $s);
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
static public function get_file_ext($arr) {
|
||||
if($arr['mimetype'] === 'text/bbcode')
|
||||
return '.bb';
|
||||
elseif($arr['mimetype'] === 'text/markdown')
|
||||
return '.md';
|
||||
elseif($arr['mimetype'] === 'text/plain')
|
||||
return '.txt';
|
||||
|
||||
}
|
||||
|
||||
// This function is derived from
|
||||
// http://stackoverflow.com/questions/32068537/generate-table-of-contents-from-markdown-in-php
|
||||
static public function toc($content) {
|
||||
// ensure using only "\n" as line-break
|
||||
$source = str_replace(["\r\n", "\r"], "\n", $content);
|
||||
|
||||
// look for markdown TOC items
|
||||
preg_match_all(
|
||||
'/^(?:=|-|#).*$/m',
|
||||
$source,
|
||||
$matches,
|
||||
PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
|
||||
);
|
||||
|
||||
// preprocess: iterate matched lines to create an array of items
|
||||
// where each item is an array(level, text)
|
||||
$file_size = strlen($source);
|
||||
foreach ($matches[0] as $item) {
|
||||
$found_mark = substr($item[0], 0, 1);
|
||||
if ($found_mark == '#') {
|
||||
// text is the found item
|
||||
$item_text = $item[0];
|
||||
$item_level = strrpos($item_text, '#') + 1;
|
||||
$item_text = substr($item_text, $item_level);
|
||||
} else {
|
||||
// text is the previous line (empty if <hr>)
|
||||
$item_offset = $item[1];
|
||||
$prev_line_offset = strrpos($source, "\n", -($file_size - $item_offset + 2));
|
||||
$item_text =
|
||||
substr($source, $prev_line_offset, $item_offset - $prev_line_offset - 1);
|
||||
$item_text = trim($item_text);
|
||||
$item_level = $found_mark == '=' ? 1 : 2;
|
||||
}
|
||||
if (!trim($item_text) OR strpos($item_text, '|') !== FALSE) {
|
||||
// item is an horizontal separator or a table header, don't mind
|
||||
continue;
|
||||
}
|
||||
$raw_toc[] = ['level' => $item_level, 'text' => trim($item_text)];
|
||||
}
|
||||
$o = '';
|
||||
foreach($raw_toc as $t) {
|
||||
$level = intval($t['level']);
|
||||
$text = $t['text'];
|
||||
switch ($level) {
|
||||
case 1:
|
||||
$li = '* ';
|
||||
break;
|
||||
case 2:
|
||||
$li = ' * ';
|
||||
break;
|
||||
case 3:
|
||||
$li = ' * ';
|
||||
break;
|
||||
case 4:
|
||||
$li = ' * ';
|
||||
break;
|
||||
default:
|
||||
$li = '* ';
|
||||
break;
|
||||
}
|
||||
$o .= $li . $text . "\n";
|
||||
}
|
||||
return $o;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
|
||||
/**
|
||||
* @brief Class for handling channel specific configurations.
|
||||
*
|
||||
@@ -32,15 +34,15 @@ class PConfig {
|
||||
if(is_null($uid) || $uid === false)
|
||||
return false;
|
||||
|
||||
if(! is_array(\App::$config)) {
|
||||
if(! is_array(App::$config)) {
|
||||
btlogger('App::$config not an array');
|
||||
}
|
||||
|
||||
if(! array_key_exists($uid, \App::$config)) {
|
||||
\App::$config[$uid] = array();
|
||||
if(! array_key_exists($uid, App::$config)) {
|
||||
App::$config[$uid] = array();
|
||||
}
|
||||
|
||||
if(! is_array(\App::$config[$uid])) {
|
||||
if(! is_array(App::$config[$uid])) {
|
||||
btlogger('App::$config[$uid] not an array: ' . $uid);
|
||||
}
|
||||
|
||||
@@ -52,12 +54,12 @@ class PConfig {
|
||||
foreach($r as $rr) {
|
||||
$k = $rr['k'];
|
||||
$c = $rr['cat'];
|
||||
if(! array_key_exists($c, \App::$config[$uid])) {
|
||||
\App::$config[$uid][$c] = array();
|
||||
\App::$config[$uid][$c]['config_loaded'] = true;
|
||||
if(! array_key_exists($c, App::$config[$uid])) {
|
||||
App::$config[$uid][$c] = array();
|
||||
App::$config[$uid][$c]['config_loaded'] = true;
|
||||
}
|
||||
\App::$config[$uid][$c][$k] = $rr['v'];
|
||||
\App::$config[$uid][$c]['pcfgud:'.$k] = $rr['updated'];
|
||||
App::$config[$uid][$c][$k] = $rr['v'];
|
||||
App::$config[$uid][$c]['pcfgud:'.$k] = $rr['updated'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,15 +88,15 @@ class PConfig {
|
||||
if(is_null($uid) || $uid === false)
|
||||
return $default;
|
||||
|
||||
if(! array_key_exists($uid, \App::$config))
|
||||
if(! array_key_exists($uid, App::$config))
|
||||
self::Load($uid);
|
||||
|
||||
if((! array_key_exists($family, \App::$config[$uid])) || (! array_key_exists($key, \App::$config[$uid][$family])))
|
||||
if((! array_key_exists($family, App::$config[$uid])) || (! array_key_exists($key, App::$config[$uid][$family])))
|
||||
return $default;
|
||||
|
||||
return ((! is_array(\App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$uid][$family][$key]))
|
||||
? unserialize(\App::$config[$uid][$family][$key])
|
||||
: \App::$config[$uid][$family][$key]
|
||||
return ((! is_array(App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', App::$config[$uid][$family][$key]))
|
||||
? unserialize(App::$config[$uid][$family][$key])
|
||||
: App::$config[$uid][$family][$key]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -132,6 +134,8 @@ class PConfig {
|
||||
// manage array value
|
||||
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
|
||||
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
|
||||
$new = false;
|
||||
$update = false;
|
||||
|
||||
$now = datetime_convert();
|
||||
if (! $updated) {
|
||||
@@ -142,23 +146,22 @@ class PConfig {
|
||||
$updated = datetime_convert('UTC','UTC','-2 seconds');
|
||||
}
|
||||
|
||||
$hash = hash('sha256',$family.':'.$key);
|
||||
$hash = gen_link_id($family.':'.$key);
|
||||
|
||||
if (self::Get($uid, 'hz_delpconfig', $hash) !== false) {
|
||||
if (self::Get($uid, 'hz_delpconfig', $hash) > $now) {
|
||||
logger('Refusing to update pconfig with outdated info (Item deleted more recently).', LOGGER_NORMAL, LOG_ERR);
|
||||
return self::Get($uid,$family,$key);
|
||||
} else {
|
||||
self::Delete($uid,'hz_delpconfig',$hash);
|
||||
self::Delete($uid, 'hz_delpconfig', $hash);
|
||||
}
|
||||
}
|
||||
|
||||
if(self::Get($uid, $family, $key) === false) {
|
||||
if(! array_key_exists($uid, \App::$config))
|
||||
\App::$config[$uid] = array();
|
||||
if(! array_key_exists($family, \App::$config[$uid]))
|
||||
\App::$config[$uid][$family] = array();
|
||||
|
||||
if(! array_key_exists($uid, App::$config))
|
||||
App::$config[$uid] = array();
|
||||
if(! array_key_exists($family, App::$config[$uid]))
|
||||
App::$config[$uid][$family] = array();
|
||||
|
||||
$ret = q("INSERT INTO pconfig ( uid, cat, k, v, updated ) VALUES ( %d, '%s', '%s', '%s', '%s' ) ",
|
||||
intval($uid),
|
||||
@@ -176,13 +179,14 @@ class PConfig {
|
||||
logger("Error: Insert to pconfig failed.",LOGGER_NORMAL, LOG_ERR);
|
||||
}
|
||||
|
||||
\App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
|
||||
$new = true;
|
||||
App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
|
||||
|
||||
}
|
||||
else {
|
||||
$new = (\App::$config[$uid][$family]['pcfgud:'.$key] < $now);
|
||||
$update = (App::$config[$uid][$family]['pcfgud:'.$key] < $now);
|
||||
|
||||
if ($new) {
|
||||
if ($update) {
|
||||
|
||||
// @NOTE There is still a possible race condition under limited circumstances
|
||||
// where a value will be updated by another thread with more current data than
|
||||
@@ -197,7 +201,7 @@ class PConfig {
|
||||
dbesc($key)
|
||||
);
|
||||
|
||||
\App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
|
||||
App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
|
||||
|
||||
} else {
|
||||
logger('Refusing to update pconfig with outdated info.', LOGGER_NORMAL, LOG_ERR);
|
||||
@@ -210,16 +214,16 @@ class PConfig {
|
||||
// set in the life of this page. We need this to
|
||||
// synchronise channel clones.
|
||||
|
||||
if(! array_key_exists('transient', \App::$config[$uid]))
|
||||
\App::$config[$uid]['transient'] = array();
|
||||
if(! array_key_exists($family, \App::$config[$uid]['transient']))
|
||||
\App::$config[$uid]['transient'][$family] = array();
|
||||
if(! array_key_exists('transient', App::$config[$uid]))
|
||||
App::$config[$uid]['transient'] = array();
|
||||
if(! array_key_exists($family, App::$config[$uid]['transient']))
|
||||
App::$config[$uid]['transient'][$family] = array();
|
||||
|
||||
\App::$config[$uid][$family][$key] = $value;
|
||||
App::$config[$uid][$family][$key] = $value;
|
||||
|
||||
if ($new) {
|
||||
\App::$config[$uid]['transient'][$family][$key] = $value;
|
||||
\App::$config[$uid]['transient'][$family]['pcfgud:'.$key] = $updated;
|
||||
if ($new || $update) {
|
||||
App::$config[$uid]['transient'][$family][$key] = $value;
|
||||
App::$config[$uid]['transient'][$family]['pcfgud:'.$key] = $updated;
|
||||
}
|
||||
|
||||
if($ret)
|
||||
@@ -252,7 +256,7 @@ class PConfig {
|
||||
|
||||
$updated = ($updated) ? $updated : datetime_convert('UTC','UTC','-2 seconds');
|
||||
$now = datetime_convert();
|
||||
$newer = (\App::$config[$uid][$family]['pcfgud:'.$key] < $now);
|
||||
$newer = (App::$config[$uid][$family]['pcfgud:'.$key] < $now);
|
||||
|
||||
if (! $newer) {
|
||||
logger('Refusing to delete pconfig with outdated delete request.', LOGGER_NORMAL, LOG_ERR);
|
||||
@@ -261,12 +265,12 @@ class PConfig {
|
||||
|
||||
$ret = false;
|
||||
|
||||
if (isset(\App::$config[$uid][$family][$key])) {
|
||||
unset(\App::$config[$uid][$family][$key]);
|
||||
if (isset(App::$config[$uid][$family][$key])) {
|
||||
unset(App::$config[$uid][$family][$key]);
|
||||
}
|
||||
|
||||
if (isset(\App::$config[$uid][$family]['pcfgud:'.$key])) {
|
||||
unset(\App::$config[$uid][$family]['pcfgud:'.$key]);
|
||||
if (isset(App::$config[$uid][$family]['pcfgud:'.$key])) {
|
||||
unset(App::$config[$uid][$family]['pcfgud:'.$key]);
|
||||
}
|
||||
|
||||
$ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'",
|
||||
@@ -277,9 +281,9 @@ class PConfig {
|
||||
|
||||
// Synchronize delete with clones.
|
||||
|
||||
if ($family != 'hz_delpconfig') {
|
||||
$hash = hash('sha256',$family.':'.$key);
|
||||
set_pconfig($uid,'hz_delpconfig',$hash,$updated);
|
||||
if ($family !== 'hz_delpconfig') {
|
||||
$hash = gen_link_id($family.':'.$key);
|
||||
set_pconfig($uid, 'hz_delpconfig', $hash, $updated);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Access\PermissionRoles;
|
||||
use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Daemon\Master;
|
||||
|
||||
/**
|
||||
* @brief Permission Categories. Permission rules for various classes of connections.
|
||||
@@ -38,33 +39,33 @@ class Permcat {
|
||||
|
||||
// first check role perms for a perms_connect setting
|
||||
|
||||
$role = get_pconfig($channel_id,'system','permissions_role');
|
||||
if($role) {
|
||||
$role = get_pconfig($channel_id, 'system', 'permissions_role');
|
||||
if ($role) {
|
||||
$x = PermissionRoles::role_perms($role);
|
||||
if($x['perms_connect']) {
|
||||
if ($x['perms_connect']) {
|
||||
$perms = Permissions::FilledPerms($x['perms_connect']);
|
||||
}
|
||||
}
|
||||
|
||||
// if no role perms it may be a custom role, see if there any autoperms
|
||||
|
||||
if(! $perms) {
|
||||
if (!$perms) {
|
||||
$perms = Permissions::FilledAutoPerms($channel_id);
|
||||
}
|
||||
|
||||
// if no autoperms it may be a custom role with manual perms
|
||||
|
||||
if(! $perms) {
|
||||
if (!$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) {
|
||||
$perms[$xv['k']] = intval($xv['v']);
|
||||
}
|
||||
}
|
||||
@@ -73,25 +74,27 @@ class Permcat {
|
||||
|
||||
// nothing was found - create a filled permission array where all permissions are 0
|
||||
|
||||
if(! $perms) {
|
||||
if (!$perms) {
|
||||
$perms = Permissions::FilledPerms([]);
|
||||
}
|
||||
|
||||
$this->permcats[] = [
|
||||
'name' => 'default',
|
||||
'localname' => t('default','permcat'),
|
||||
'localname' => t('Default', 'permcat'),
|
||||
'perms' => Permissions::Operms($perms),
|
||||
'raw_perms' => $perms,
|
||||
'system' => 1
|
||||
];
|
||||
|
||||
|
||||
$p = $this->load_permcats($channel_id);
|
||||
if($p) {
|
||||
for($x = 0; $x < count($p); $x++) {
|
||||
if ($p) {
|
||||
for ($x = 0; $x < count($p); $x++) {
|
||||
$this->permcats[] = [
|
||||
'name' => $p[$x][0],
|
||||
'localname' => $p[$x][1],
|
||||
'perms' => Permissions::Operms(Permissions::FilledPerms($p[$x][2])),
|
||||
'raw_perms' => Permissions::FilledPerms($p[$x][2]),
|
||||
'system' => intval($p[$x][3])
|
||||
];
|
||||
}
|
||||
@@ -116,9 +119,9 @@ class Permcat {
|
||||
* * \e bool \b error if $name not found in permcats true
|
||||
*/
|
||||
public function fetch($name) {
|
||||
if($name && $this->permcats) {
|
||||
foreach($this->permcats as $permcat) {
|
||||
if(strcasecmp($permcat['name'], $name) === 0) {
|
||||
if ($name && $this->permcats) {
|
||||
foreach ($this->permcats as $permcat) {
|
||||
if (strcasecmp($permcat['name'], $name) === 0) {
|
||||
return $permcat;
|
||||
}
|
||||
}
|
||||
@@ -128,31 +131,28 @@ class Permcat {
|
||||
}
|
||||
|
||||
public function load_permcats($uid) {
|
||||
|
||||
/*
|
||||
$permcats = [
|
||||
[ 'follower', t('follower','permcat'),
|
||||
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
|
||||
'post_like' ], 1
|
||||
],
|
||||
[ 'contributor', t('contributor','permcat'),
|
||||
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
|
||||
'post_wall','post_comments','write_wiki','post_like','tag_deliver','chat' ], 1
|
||||
],
|
||||
[ 'publisher', t('publisher','permcat'),
|
||||
[ 'contributor', t('Contributor','permcat'),
|
||||
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages',
|
||||
'write_storage','post_wall','write_pages','write_wiki','post_comments','post_like','tag_deliver',
|
||||
'chat', 'republish' ], 1
|
||||
]
|
||||
'write_storage','post_wall','write_pages','write_wiki','post_comments', 'post_mail', 'post_like',
|
||||
'chat' ], 1
|
||||
],
|
||||
[ 'muted', t('Muted','permcat'),
|
||||
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
|
||||
'post_comments','write_wiki','post_like' ], 1
|
||||
],
|
||||
];
|
||||
|
||||
if($uid) {
|
||||
*/
|
||||
if ($uid) {
|
||||
$x = q("select * from pconfig where uid = %d and cat = 'permcat'",
|
||||
intval($uid)
|
||||
);
|
||||
if($x) {
|
||||
foreach($x as $xv) {
|
||||
$value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']);
|
||||
$permcats[] = [ $xv['k'], $xv['k'], $value, 0 ];
|
||||
|
||||
if ($x) {
|
||||
foreach ($x as $xv) {
|
||||
$value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']);
|
||||
$permcats[] = [$xv['k'], $xv['k'], $value, 0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,11 +167,11 @@ class Permcat {
|
||||
}
|
||||
|
||||
static public function find_permcat($arr, $name) {
|
||||
if((! $arr) || (! $name))
|
||||
if ((!$arr) || (!$name))
|
||||
return false;
|
||||
|
||||
foreach($arr as $p)
|
||||
if($p['name'] == $name)
|
||||
foreach ($arr as $p)
|
||||
if ($p['name'] == $name)
|
||||
return $p['value'];
|
||||
}
|
||||
|
||||
@@ -183,4 +183,105 @@ class Permcat {
|
||||
PConfig::Delete($channel_id, 'permcat', $name);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief assign a contact role to contacts
|
||||
*
|
||||
* @param array $channel
|
||||
* @param string $role the name of the role
|
||||
* @param array $contacts an array of contact hashes
|
||||
*/
|
||||
public static function assign($channel, $role, $contacts) {
|
||||
|
||||
if (!isset($channel['channel_id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($contacts) || empty($contacts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$role) {
|
||||
// lookup the default
|
||||
$role = get_pconfig($channel['channel_id'], 'system', 'default_permcat', 'default');
|
||||
}
|
||||
|
||||
|
||||
// Doublecheck that we do not assign a role to ourself.
|
||||
// It does not make a difference but could be confusing.
|
||||
if (in_array($channel['channel_hash'], $contacts)) {
|
||||
$contacts = array_diff($contacts, [$channel['channel_hash']]);
|
||||
}
|
||||
|
||||
$all_perms = Permissions::Perms();
|
||||
$permcats = new Permcat($channel['channel_id']);
|
||||
$role_perms = $permcats->fetch($role);
|
||||
|
||||
if (isset($role_perms['error'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$perms = $role_perms['raw_perms'];
|
||||
|
||||
$values_sql = '';
|
||||
stringify_array_elms($contacts, true);
|
||||
|
||||
if ($all_perms && $perms) {
|
||||
|
||||
foreach ($contacts as $contact) {
|
||||
foreach ($all_perms as $perm => $desc) {
|
||||
if (array_key_exists($perm, $perms)) {
|
||||
$values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', " . intval($perms[$perm]) . "),";
|
||||
}
|
||||
else {
|
||||
$values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', 0), ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$values_sql = rtrim($values_sql, ',');
|
||||
|
||||
dbq("DELETE FROM abconfig WHERE chan = " . intval($channel['channel_id']) . " AND cat = 'my_perms' AND xchan IN (" . protect_sprintf(implode(',', $contacts)) . ")");
|
||||
|
||||
dbq("INSERT INTO abconfig ( chan, xchan, cat, k, v ) VALUES $values_sql");
|
||||
|
||||
q("UPDATE abook SET abook_role = '%s'
|
||||
WHERE abook_xchan IN (" . protect_sprintf(implode(',', $contacts)) . ") AND abook_channel = %d",
|
||||
dbesc($role),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
$r = q("SELECT abook.*, xchan.* FROM abook LEFT JOIN xchan ON abook.abook_xchan = xchan.xchan_hash WHERE abook.abook_xchan IN (" . protect_sprintf(implode(',', $contacts)) . ") AND abook.abook_channel = %d AND abook_self = 0",
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
foreach ($r as $rr) {
|
||||
|
||||
if (intval($rr['abook_self'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Master::Summon([
|
||||
'Notifier',
|
||||
'permission_update',
|
||||
$rr['abook_id']
|
||||
]);
|
||||
|
||||
$clone = $rr;
|
||||
|
||||
unset($clone['abook_id']);
|
||||
unset($clone['abook_account']);
|
||||
unset($clone['abook_channel']);
|
||||
|
||||
$abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']);
|
||||
if ($abconfig)
|
||||
$clone['abconfig'] = $abconfig;
|
||||
|
||||
Libsync::build_sync_packet(0 /* use the current local_channel */, ['abook' => [$clone]]);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
@@ -110,21 +110,30 @@ class Queue {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hash = $arr['hash'] ?? '';
|
||||
$account_id = $arr['account_id'] ?? 0;
|
||||
$channel_id = $arr['channel_id'] ?? 0;
|
||||
$driver = $arr['driver'] ?? 'zot6';
|
||||
$posturl = $arr['posturl'] ?? '';
|
||||
$priority = $arr['priority'] ?? 0;
|
||||
$notify = $arr['notify'] ?? '';
|
||||
$msg = $arr['msg'] ?? '';
|
||||
|
||||
$x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority,
|
||||
outq_created, outq_updated, outq_scheduled, outq_notify, outq_msg )
|
||||
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['posturl']),
|
||||
dbesc($hash),
|
||||
intval($account_id),
|
||||
intval($channel_id),
|
||||
dbesc($driver),
|
||||
dbesc($posturl),
|
||||
intval(1),
|
||||
intval(($arr['priority']) ? $arr['priority'] : 0),
|
||||
intval($priority),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($arr['notify']),
|
||||
dbesc(($arr['msg']) ? $arr['msg'] : '')
|
||||
dbesc($notify),
|
||||
dbesc($msg)
|
||||
);
|
||||
return $x;
|
||||
|
||||
@@ -136,8 +145,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 +159,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 +170,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 +183,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);
|
||||
@@ -244,13 +204,14 @@ class Queue {
|
||||
$channel = null;
|
||||
|
||||
if($outq['outq_channel']) {
|
||||
$channel = channelx_by_n($outq['outq_channel']);
|
||||
$channel = channelx_by_n($outq['outq_channel'], true);
|
||||
}
|
||||
|
||||
$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' and hubloc_sitekey != '' 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' AND hubloc_deleted = 0 ORDER BY hubloc_primary DESC, hubloc_id DESC LIMIT 1",
|
||||
dbesc($base)
|
||||
);
|
||||
if($h) {
|
||||
@@ -260,7 +221,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 +230,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;
|
||||
|
||||
357
Zotlabs/Lib/QueueWorker.php
Normal file
357
Zotlabs/Lib/QueueWorker.php
Normal file
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
|
||||
|
||||
class QueueWorker {
|
||||
|
||||
public static $queueworker = null;
|
||||
public static $maxworkers = 0;
|
||||
public static $workermaxage = 0;
|
||||
public static $workersleep = 100;
|
||||
public static $default_priorities = [
|
||||
'Notifier' => 10,
|
||||
'Deliver' => 10,
|
||||
'Cache_query' => 10,
|
||||
'Content_importer' => 1,
|
||||
'File_importer' => 1,
|
||||
'Channel_purge' => 1,
|
||||
'Directory' => 1
|
||||
];
|
||||
|
||||
// Exceptions for processtimeout ($workermaxage) value.
|
||||
// Currently the value is overriden with 3600 seconds (1h).
|
||||
public static $long_running_cmd = [
|
||||
'Queue'
|
||||
];
|
||||
|
||||
private static function qstart() {
|
||||
q('START TRANSACTION');
|
||||
}
|
||||
|
||||
private static function qcommit() {
|
||||
q("COMMIT");
|
||||
}
|
||||
|
||||
private static function qrollback() {
|
||||
q("ROLLBACK");
|
||||
}
|
||||
|
||||
public static function Summon($argv) {
|
||||
|
||||
if ($argv[0] !== 'Queueworker') {
|
||||
|
||||
$priority = 0; // @TODO allow reprioritization
|
||||
|
||||
if (isset(self::$default_priorities[$argv[0]])) {
|
||||
$priority = self::$default_priorities[$argv[0]];
|
||||
}
|
||||
|
||||
$workinfo = ['argc' => count($argv), 'argv' => $argv];
|
||||
$workinfo_json = json_encode($workinfo);
|
||||
$uuid = self::getUuid($workinfo_json);
|
||||
|
||||
$r = q("SELECT * FROM workerq WHERE workerq_uuid = '%s'",
|
||||
dbesc($uuid)
|
||||
);
|
||||
if ($r) {
|
||||
logger("Summon: Ignoring duplicate workerq task", LOGGER_DEBUG);
|
||||
logger(print_r($workinfo, true));
|
||||
return;
|
||||
}
|
||||
|
||||
self::qstart();
|
||||
$r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')",
|
||||
intval($priority),
|
||||
$workinfo_json,
|
||||
dbesc($uuid),
|
||||
dbesc($argv[0])
|
||||
);
|
||||
if (!$r) {
|
||||
self::qrollback();
|
||||
logger("INSERT FAILED", LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
self::qcommit();
|
||||
logger('INSERTED: ' . $workinfo_json, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
$workers = self::GetWorkerCount();
|
||||
if ($workers < self::$maxworkers) {
|
||||
logger($workers . '/' . self::$maxworkers . ' workers active', LOGGER_DEBUG);
|
||||
$phpbin = get_config('system', 'phpbin', 'php');
|
||||
proc_run($phpbin, 'Zotlabs/Daemon/Master.php', ['Queueworker']);
|
||||
}
|
||||
}
|
||||
|
||||
public static function Release($argv) {
|
||||
|
||||
if ($argv[0] !== 'Queueworker') {
|
||||
|
||||
$priority = 0; // @TODO allow reprioritization
|
||||
if (isset(self::$default_priorities[$argv[0]])) {
|
||||
$priority = self::$default_priorities[$argv[0]];
|
||||
}
|
||||
|
||||
$workinfo = ['argc' => count($argv), 'argv' => $argv];
|
||||
$workinfo_json = json_encode($workinfo);
|
||||
$uuid = self::getUuid($workinfo_json);
|
||||
|
||||
$r = q("SELECT * FROM workerq WHERE workerq_uuid = '%s'",
|
||||
dbesc($uuid)
|
||||
);
|
||||
if ($r) {
|
||||
logger("Release: Duplicate task - do not insert.", LOGGER_DEBUG);
|
||||
logger(print_r($workinfo, true));
|
||||
return;
|
||||
}
|
||||
|
||||
self::qstart();
|
||||
$r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')",
|
||||
intval($priority),
|
||||
$workinfo_json,
|
||||
dbesc($uuid),
|
||||
dbesc($argv[0])
|
||||
);
|
||||
if (!$r) {
|
||||
self::qrollback();
|
||||
logger("Insert failed: " . $workinfo_json, LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
self::qcommit();
|
||||
logger('INSERTED: ' . $workinfo_json, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
self::Process();
|
||||
}
|
||||
|
||||
public static function GetWorkerCount() {
|
||||
if (self::$maxworkers == 0) {
|
||||
self::$maxworkers = get_config('queueworker', 'max_queueworkers', 4);
|
||||
self::$maxworkers = self::$maxworkers > 3 ? self::$maxworkers : 4;
|
||||
}
|
||||
if (self::$workermaxage == 0) {
|
||||
self::$workermaxage = get_config('queueworker', 'max_queueworker_age');
|
||||
self::$workermaxage = self::$workermaxage > 120 ? self::$workermaxage : 300;
|
||||
}
|
||||
|
||||
q("update workerq set workerq_reservationid = null where workerq_reservationid is not null and workerq_processtimeout < %s",
|
||||
db_utcnow()
|
||||
);
|
||||
|
||||
//usleep(self::$workersleep);
|
||||
|
||||
$workers = dbq("select count(distinct workerq_reservationid) as total from workerq where workerq_reservationid is not null");
|
||||
logger("WORKERCOUNT: " . $workers[0]['total'], LOGGER_DEBUG);
|
||||
|
||||
return intval($workers[0]['total']);
|
||||
}
|
||||
|
||||
public static function GetWorkerID() {
|
||||
if (self::$queueworker) {
|
||||
return self::$queueworker;
|
||||
}
|
||||
|
||||
$wid = uniqid('', true);
|
||||
|
||||
usleep(mt_rand(300000, 1000000)); //Sleep .3 - 1 seconds before creating a new worker.
|
||||
|
||||
$workers = self::GetWorkerCount();
|
||||
|
||||
if ($workers >= self::$maxworkers) {
|
||||
logger("Too many active workers ($workers) max = " . self::$maxworkers, LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$queueworker = $wid;
|
||||
|
||||
return $wid;
|
||||
}
|
||||
|
||||
private static function getWorkId() {
|
||||
self::GetWorkerCount();
|
||||
|
||||
self::qstart();
|
||||
|
||||
// This is probably the better solution but is not supported by mariadb < 10.6 which is still used a lot.
|
||||
// $work = dbq("SELECT workerq_id FROM workerq WHERE workerq_reservationid IS NULL ORDER BY workerq_priority DESC, workerq_id ASC LIMIT 1 FOR UPDATE SKIP LOCKED;");
|
||||
|
||||
$work = dbq("SELECT workerq_id, workerq_cmd FROM workerq WHERE workerq_reservationid IS NULL ORDER BY workerq_priority DESC, workerq_id ASC LIMIT 1 FOR UPDATE;");
|
||||
|
||||
if (!$work) {
|
||||
self::qcommit();
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $work[0]['workerq_id'];
|
||||
$cmd = $work[0]['workerq_cmd'];
|
||||
$age = self::$workermaxage;
|
||||
|
||||
if (in_array($cmd, self::$long_running_cmd)) {
|
||||
$age = 3600; // 1h TODO: make this configurable
|
||||
}
|
||||
|
||||
$work = q("UPDATE workerq SET workerq_reservationid = '%s', workerq_processtimeout = %s + INTERVAL %s WHERE workerq_id = %d",
|
||||
self::$queueworker,
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . " SECOND"),
|
||||
intval($id)
|
||||
);
|
||||
|
||||
if (!$work) {
|
||||
self::qrollback();
|
||||
logger("Could not update workerq.", LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
logger("GOTWORK: " . json_encode($work), LOGGER_DEBUG);
|
||||
self::qcommit();
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public static function Process() {
|
||||
$sleep = intval(get_config('queueworker', 'queue_worker_sleep', 100));
|
||||
$auto_queue_worker_sleep = get_config('queueworker', 'auto_queue_worker_sleep', 0);
|
||||
|
||||
if (!self::GetWorkerID()) {
|
||||
if ($auto_queue_worker_sleep) {
|
||||
set_config('queueworker', 'queue_worker_sleep', $sleep + 100);
|
||||
}
|
||||
|
||||
logger('Unable to get worker ID. Exiting.', LOGGER_DEBUG);
|
||||
killme();
|
||||
}
|
||||
|
||||
if ($auto_queue_worker_sleep && $sleep > 100) {
|
||||
$next_sleep = $sleep - 100;
|
||||
set_config('queueworker', 'queue_worker_sleep', (($next_sleep < 100) ? 100 : $next_sleep));
|
||||
}
|
||||
|
||||
$jobs = 0;
|
||||
$workid = self::getWorkId();
|
||||
$load_average_sleep = false;
|
||||
self::$workersleep = $sleep;
|
||||
self::$workersleep = ((intval(self::$workersleep) > 100) ? intval(self::$workersleep) : 100);
|
||||
|
||||
if (function_exists('sys_getloadavg') && get_config('queueworker', 'load_average_sleep')) {
|
||||
// very experimental!
|
||||
$load_average_sleep = true;
|
||||
}
|
||||
|
||||
while ($workid) {
|
||||
|
||||
if ($load_average_sleep) {
|
||||
$load_average = sys_getloadavg();
|
||||
self::$workersleep = intval($load_average[0]) * 10000;
|
||||
|
||||
if (!self::$workersleep) {
|
||||
self::$workersleep = 100;
|
||||
}
|
||||
}
|
||||
|
||||
logger('queue_worker_sleep: ' . self::$workersleep, LOGGER_DEBUG);
|
||||
|
||||
usleep(self::$workersleep);
|
||||
|
||||
$workitem = dbq("SELECT * FROM workerq WHERE workerq_id = $workid");
|
||||
|
||||
if ($workitem) {
|
||||
// At least SOME work to do.... in case there's more, let's ramp up workers.
|
||||
$workers = self::GetWorkerCount();
|
||||
|
||||
if ($workers < self::$maxworkers) {
|
||||
logger($workers . '/' . self::$maxworkers . ' workers active', LOGGER_DEBUG);
|
||||
$phpbin = get_config('system', 'phpbin', 'php');
|
||||
proc_run($phpbin, 'Zotlabs/Daemon/Master.php', ['Queueworker']);
|
||||
}
|
||||
|
||||
$jobs++;
|
||||
|
||||
logger("Workinfo: " . $workitem[0]['workerq_data'], LOGGER_DEBUG);
|
||||
|
||||
$workinfo = json_decode($workitem[0]['workerq_data'], true);
|
||||
$argv = $workinfo['argv'];
|
||||
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$argv = flatten_array_recursive($argv);
|
||||
$argc = count($argv);
|
||||
$rnd = random_string();
|
||||
|
||||
logger('PROCESSING: ' . $rnd . ' ' . print_r($argv[0], true));
|
||||
|
||||
$cls::run($argc, $argv);
|
||||
|
||||
logger('COMPLETED: ' . $rnd);
|
||||
|
||||
// @FIXME: Right now we assume that if we get a return, everything is OK.
|
||||
// At some point we may want to test whether the run returns true/false
|
||||
// and requeue the work to be tried again if needed. But we probably want
|
||||
// to implement some sort of "retry interval" first.
|
||||
|
||||
dbq("delete from workerq where workerq_id = $workid");
|
||||
}
|
||||
else {
|
||||
logger("NO WORKITEM!", LOGGER_DEBUG);
|
||||
}
|
||||
$workid = self::getWorkId();
|
||||
}
|
||||
logger('Master: Worker Thread: queue items processed:' . $jobs, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
public static function ClearQueue() {
|
||||
$work = q("select * from workerq");
|
||||
while ($work) {
|
||||
foreach ($work as $workitem) {
|
||||
$workinfo = json_decode($workitem['v'], true);
|
||||
$argc = $workinfo['argc'];
|
||||
$argv = $workinfo['argv'];
|
||||
|
||||
logger('Master: process: ' . print_r($argv, true), LOGGER_ALL, LOG_DEBUG);
|
||||
|
||||
if (!isset($argv[0])) {
|
||||
q("delete from workerq where workerq_id = %d",
|
||||
$work[0]['workerq_id']
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$cls::run($argc, $argv);
|
||||
|
||||
q("delete from workerq where workerq_id = %d",
|
||||
$work[0]['workerq_id']
|
||||
);
|
||||
|
||||
//Give the server .3 seconds to catch its breath between tasks.
|
||||
//This will hopefully keep it from crashing to it's knees entirely
|
||||
//if the last task ended up initiating other parallel processes
|
||||
//(eg. polling remotes)
|
||||
usleep(300000);
|
||||
}
|
||||
|
||||
//Make sure nothing new came in
|
||||
$work = q("select * from workerq");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate a name-based v5 UUID with custom namespace
|
||||
*
|
||||
* @param string $data
|
||||
* @return string $uuid
|
||||
*/
|
||||
private static function getUuid(string $data) {
|
||||
$namespace = '3a112e42-f147-4ccf-a78b-f6841339ea2a';
|
||||
try {
|
||||
$uuid = Uuid::uuid5($namespace, $data)->toString();
|
||||
} catch (UnableToBuildUuidException $e) {
|
||||
logger('UUID generation failed');
|
||||
return '';
|
||||
}
|
||||
return $uuid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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]";
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ class System {
|
||||
}
|
||||
|
||||
static public function get_site_name() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['sitename'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['sitename']))
|
||||
return \App::$config['system']['sitename'];
|
||||
return '';
|
||||
}
|
||||
|
||||
static public function get_project_version() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['hide_version'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['hide_version']))
|
||||
return '';
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('std_version',\App::$config['system']))
|
||||
return \App::$config['system']['std_version'];
|
||||
@@ -31,33 +31,33 @@ class System {
|
||||
}
|
||||
|
||||
static public function get_update_version() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['hide_version'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['hide_version']))
|
||||
return '';
|
||||
return DB_UPDATE_VERSION;
|
||||
}
|
||||
|
||||
|
||||
static public function get_notify_icon() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['email_notify_icon_url'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['email_notify_icon_url']))
|
||||
return \App::$config['system']['email_notify_icon_url'];
|
||||
return z_root() . DEFAULT_NOTIFY_ICON;
|
||||
}
|
||||
|
||||
static public function get_site_icon() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['site_icon_url'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['site_icon_url']))
|
||||
return \App::$config['system']['site_icon_url'];
|
||||
return z_root() . DEFAULT_PLATFORM_ICON ;
|
||||
}
|
||||
|
||||
|
||||
static public function get_project_link() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['project_link'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['project_link']))
|
||||
return \App::$config['system']['project_link'];
|
||||
return 'https://hubzilla.org';
|
||||
}
|
||||
|
||||
static public function get_project_srclink() {
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['project_srclink'])
|
||||
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['project_srclink']))
|
||||
return \App::$config['system']['project_srclink'];
|
||||
return 'https://framagit.org/hubzilla/core.git';
|
||||
}
|
||||
@@ -68,7 +68,7 @@ class System {
|
||||
|
||||
|
||||
static public function get_zot_revision() {
|
||||
$x = [ 'revision' => ZOT_REVISION ];
|
||||
$x = [ 'revision' => ZOT_REVISION ];
|
||||
call_hooks('zot_revision',$x);
|
||||
return $x['revision'];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Access\AccessList;
|
||||
|
||||
require_once('include/text.php');
|
||||
|
||||
@@ -35,7 +37,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 +45,7 @@ class ThreadItem {
|
||||
$observer = \App::get_observer();
|
||||
|
||||
// Prepare the children
|
||||
if($data['children']) {
|
||||
if(isset($data['children'])) {
|
||||
foreach($data['children'] as $item) {
|
||||
|
||||
/*
|
||||
@@ -58,6 +60,9 @@ class ThreadItem {
|
||||
$child = new ThreadItem($item);
|
||||
$this->add_child($child);
|
||||
}
|
||||
|
||||
// performance: we have already added the children
|
||||
unset($this->data['children']);
|
||||
}
|
||||
|
||||
// allow a site to configure the order and content of the reaction emoji list
|
||||
@@ -79,10 +84,8 @@ class ThreadItem {
|
||||
|
||||
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
|
||||
|
||||
$result = array();
|
||||
|
||||
$item = $this->get_data();
|
||||
|
||||
$result = [];
|
||||
$item = $this->get_data();
|
||||
$commentww = '';
|
||||
$sparkle = '';
|
||||
$buttons = '';
|
||||
@@ -93,32 +96,51 @@ class ThreadItem {
|
||||
$is_item = false;
|
||||
$osparkle = '';
|
||||
$total_children = $this->count_descendants();
|
||||
$unseen_comments = (($item['real_uid']) ? 0 : $this->count_unseen_descendants());
|
||||
$unseen_comments = ((isset($item['real_uid']) && $item['real_uid']) ? 0 : $this->count_unseen_descendants());
|
||||
|
||||
$conv = $this->get_conversation();
|
||||
$observer = $conv->get_observer();
|
||||
|
||||
$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')
|
||||
$acl = new AccessList(false);
|
||||
$acl->set($item);
|
||||
|
||||
$lock = ((intval($item['item_private']) || ($item['uid'] == local_channel() && $acl->is_private()))
|
||||
? t('Restricted message')
|
||||
: false);
|
||||
|
||||
// 1 = restricted message, 2 = direct message
|
||||
$locktype = intval($item['item_private']);
|
||||
|
||||
if ($locktype === 2) {
|
||||
$lock = t('Direct message');
|
||||
}
|
||||
|
||||
// 0 = limited based on public policy
|
||||
if ($item['uid'] == local_channel() && intval($item['item_private']) && !$acl->is_private() && strlen($item['public_policy'])) {
|
||||
$lock = t('Public Policy');
|
||||
$locktype = 0;
|
||||
}
|
||||
|
||||
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false);
|
||||
|
||||
// allow an exemption for sharing stuff from your private feeds
|
||||
if($item['author']['xchan_network'] === 'rss')
|
||||
$shareable = true;
|
||||
|
||||
$privacy_warning = false;
|
||||
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
|
||||
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
|
||||
// @fixme
|
||||
// Have recently added code to properly handle polls in group reshares by redirecting all of the poll responses to the group.
|
||||
// Sharing a poll using a regular embedded share is harder because the poll will need to fork. This is due to comment permissions.
|
||||
// The original poll author may not accept responses from strangers. Forking the poll will receive responses from the sharer's
|
||||
// followers, but there's no elegant way to merge these two sets of results together. For now, we'll disable sharing polls.
|
||||
|
||||
if(! in_array($observer['xchan_url'], $recips['to']))
|
||||
$privacy_warning = true;
|
||||
if ($item['obj_type'] === 'Question') {
|
||||
$shareable = false;
|
||||
}
|
||||
|
||||
$privacy_warning = ($item['owner']['xchan_network'] === 'activitypub' && intval($item['item_private']) === 1);
|
||||
|
||||
if ($lock) {
|
||||
if (($item['mid'] == $item['parent_mid']) && count(get_terms_oftype($item['term'],TERM_FORUM))) {
|
||||
if (($item['mid'] == $item['parent_mid']) && isset($item['term']) && count(get_terms_oftype($item['term'], TERM_FORUM))) {
|
||||
$privacy_warning = true;
|
||||
$conv_flags['parent_privacy_warning'] = true;
|
||||
}
|
||||
@@ -132,27 +154,16 @@ class ThreadItem {
|
||||
|
||||
$mode = $conv->get_mode();
|
||||
|
||||
switch($item['item_type']) {
|
||||
case ITEM_TYPE_CARD:
|
||||
$edlink = 'card_edit';
|
||||
break;
|
||||
case ITEM_TYPE_ARTICLE:
|
||||
$edlink = 'article_edit';
|
||||
break;
|
||||
default:
|
||||
$edlink = 'editpost';
|
||||
break;
|
||||
}
|
||||
|
||||
if(local_channel() && $observer['xchan_hash'] === $item['author_xchan'])
|
||||
$edpost = array(z_root() . '/' . $edlink . '/' . $item['id'], t('Edit'));
|
||||
$edpost = array(z_root() . '/editpost/' . $item['id'], t('Edit'));
|
||||
else
|
||||
$edpost = false;
|
||||
|
||||
|
||||
if($observer['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;
|
||||
|
||||
|
||||
@@ -161,24 +172,17 @@ class ThreadItem {
|
||||
$dropping = false;
|
||||
}
|
||||
|
||||
|
||||
$drop = [];
|
||||
if($dropping) {
|
||||
$drop = array(
|
||||
'dropping' => $dropping,
|
||||
'delete' => t('Delete'),
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif(is_site_admin()) {
|
||||
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
|
||||
}
|
||||
|
||||
// FIXME
|
||||
if($observer_is_pageowner) {
|
||||
$multidrop = array(
|
||||
'select' => t('Select'),
|
||||
);
|
||||
}
|
||||
|
||||
$filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) ? t("Save to Folder") : false);
|
||||
|
||||
$profile_avatar = $item['author']['xchan_photo_m'];
|
||||
@@ -188,7 +192,6 @@ class ThreadItem {
|
||||
$location = format_location($item);
|
||||
$isevent = false;
|
||||
$attend = null;
|
||||
$canvote = false;
|
||||
|
||||
// process action responses - e.g. like/dislike/attend/agree/whatever
|
||||
$response_verbs = array('like');
|
||||
@@ -208,25 +211,15 @@ class ThreadItem {
|
||||
$response_verbs[] = 'answer';
|
||||
}
|
||||
|
||||
$consensus = (intval($item['item_consensus']) ? true : false);
|
||||
if($consensus) {
|
||||
$response_verbs[] = 'agree';
|
||||
$response_verbs[] = 'disagree';
|
||||
$response_verbs[] = 'abstain';
|
||||
if($this->is_commentable() && $observer) {
|
||||
$conlabels = array( t('I agree'), t('I disagree'), t('I abstain'));
|
||||
$canvote = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(! feature_enabled($conv->get_profile_owner(),'dislike'))
|
||||
unset($conv_responses['dislike']);
|
||||
|
||||
|
||||
$responses = get_responses($conv_responses,$response_verbs,$this,$item);
|
||||
|
||||
$my_responses = [];
|
||||
foreach($response_verbs as $v) {
|
||||
$my_responses[$v] = (($conv_responses[$v][$item['mid'] . '-m']) ? 1 : 0);
|
||||
|
||||
$my_responses[$v] = ((isset($conv_responses[$v][$item['mid'] . '-m'])) ? 1 : 0);
|
||||
}
|
||||
|
||||
$like_count = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid']] : '');
|
||||
@@ -239,6 +232,7 @@ class ThreadItem {
|
||||
}
|
||||
$like_button_label = tt('Like','Likes',$like_count,'noun');
|
||||
|
||||
$showdislike = '';
|
||||
if (feature_enabled($conv->get_profile_owner(),'dislike')) {
|
||||
$dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : '');
|
||||
$dislike_list = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid'] . '-l'] : '');
|
||||
@@ -249,11 +243,11 @@ class ThreadItem {
|
||||
} else {
|
||||
$dislike_list_part = '';
|
||||
}
|
||||
|
||||
$showdislike = ((x($conv_responses['dislike'],$item['mid'])) ? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : '');
|
||||
}
|
||||
|
||||
$showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : '');
|
||||
$showdislike = ((x($conv_responses['dislike'],$item['mid']) && feature_enabled($conv->get_profile_owner(),'dislike'))
|
||||
? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : '');
|
||||
|
||||
/*
|
||||
* We should avoid doing this all the time, but it depends on the conversation mode
|
||||
@@ -262,18 +256,15 @@ class ThreadItem {
|
||||
*/
|
||||
|
||||
$this->check_wall_to_wall();
|
||||
|
||||
if($this->is_toplevel()) {
|
||||
// FIXME check this permission
|
||||
if(($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) {
|
||||
|
||||
$star = array(
|
||||
if($this->is_toplevel()) {
|
||||
if((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) {
|
||||
$star = [
|
||||
'toggle' => t("Toggle Star Status"),
|
||||
'isstarred' => ((intval($item['item_starred'])) ? true : false),
|
||||
);
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$is_comment = true;
|
||||
}
|
||||
@@ -285,18 +276,22 @@ class ThreadItem {
|
||||
|
||||
$settings = '';
|
||||
|
||||
$tagger = [];
|
||||
|
||||
// FIXME - check this permission
|
||||
if($conv->get_profile_owner() == local_channel()) {
|
||||
if(local_channel() && $conv->get_profile_owner() == local_channel()) {
|
||||
/* disable until we agree on how to implemnt this in zot6/activitypub
|
||||
$tagger = array(
|
||||
'tagit' => t("Add Tag"),
|
||||
'classtagger' => "",
|
||||
);
|
||||
*/
|
||||
|
||||
$settings = t('Conversation Tools');
|
||||
$settings = t('Conversation Features');
|
||||
}
|
||||
|
||||
$has_bookmarks = false;
|
||||
if(Apps::system_app_installed(local_channel(), 'Bookmarks') && is_array($item['term'])) {
|
||||
if(Apps::system_app_installed(local_channel(), 'Bookmarks') && isset($item['term']) && is_array($item['term'])) {
|
||||
foreach($item['term'] as $t) {
|
||||
if(($t['ttype'] == TERM_BOOKMARK))
|
||||
$has_bookmarks = true;
|
||||
@@ -307,20 +302,26 @@ class ThreadItem {
|
||||
if(($item['obj_type'] === ACTIVITY_OBJ_EVENT) && $conv->get_profile_owner() == local_channel())
|
||||
$has_event = true;
|
||||
|
||||
$like = [];
|
||||
$dislike = [];
|
||||
$reply_to = [];
|
||||
|
||||
if($this->is_commentable() && $observer) {
|
||||
$like = array( t("I like this \x28toggle\x29"), t("like"));
|
||||
$dislike = array( t("I don't like this \x28toggle\x29"), t("dislike"));
|
||||
$reply_to = array( t("Reply on this comment"), t("reply"), t("Reply to"));
|
||||
}
|
||||
|
||||
$share = [];
|
||||
$embed = [];
|
||||
if ($shareable) {
|
||||
// This actually turns out not to be possible in some protocol stacks without opening up hundreds of new issues.
|
||||
// Will allow it only for uri resolvable sources.
|
||||
if(strpos($item['mid'],'http') === 0) {
|
||||
$share = []; //Not yet ready for primetime
|
||||
//Not yet ready for primetime
|
||||
//$share = array( t('Repeat This'), t('repeat'));
|
||||
}
|
||||
$embed = array( t('Share This'), t('share'));
|
||||
$embed = [t('Share This'), t('share')];
|
||||
}
|
||||
|
||||
$dreport = '';
|
||||
@@ -329,11 +330,13 @@ class ThreadItem {
|
||||
if($keep_reports === 0)
|
||||
$keep_reports = 10;
|
||||
|
||||
if((! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) {
|
||||
$dreport_link = '';
|
||||
if((intval($item['item_type']) == ITEM_TYPE_POST) && (! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) {
|
||||
$dreport = t('Delivery Report');
|
||||
$dreport_link = gen_link_id($item['mid']);
|
||||
}
|
||||
|
||||
$is_new = false;
|
||||
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
|
||||
$is_new = true;
|
||||
|
||||
@@ -343,15 +346,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( t('%d unseen'),$unseen_comments) : '');
|
||||
|
||||
$comment_count_txt = sprintf(tt('%d Comment', '%d Comments', $total_children), $total_children);
|
||||
$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);
|
||||
@@ -360,7 +363,7 @@ class ThreadItem {
|
||||
call_hooks('dropdown_extras',$dropdown_extras_arr);
|
||||
$dropdown_extras = $dropdown_extras_arr['dropdown_extras'];
|
||||
|
||||
$midb64 = 'b64.' . base64url_encode($item['mid']);
|
||||
$midb64 = gen_link_id($item['mid']);
|
||||
$mids = [ $midb64 ];
|
||||
$response_mids = [];
|
||||
foreach($response_verbs as $v) {
|
||||
@@ -377,10 +380,16 @@ class ThreadItem {
|
||||
$pinned_items = ($allowed_type ? get_pconfig($item['uid'], 'pinned', $item['item_type'], []) : []);
|
||||
$pinned = ((!empty($pinned_items) && in_array($midb64, $pinned_items)) ? true : false);
|
||||
|
||||
$contact = [];
|
||||
|
||||
if(App::$contacts && array_key_exists($item['author_xchan'], App::$contacts)) {
|
||||
$contact = App::$contacts[$item['author_xchan']];
|
||||
}
|
||||
|
||||
$tmp_item = array(
|
||||
'template' => $this->get_template(),
|
||||
'mode' => $mode,
|
||||
'item_type' => intval($item['item_type']),
|
||||
'item_type' => intval($item['item_type']),
|
||||
//'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
|
||||
'body' => $body['html'],
|
||||
'tags' => $body['tags'],
|
||||
@@ -394,11 +403,9 @@ class ThreadItem {
|
||||
'mids' => $json_mids,
|
||||
'parent' => $item['parent'],
|
||||
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
||||
'author_is_group_actor' => (($item['author']['xchan_pubforum']) ? t('Forum') : ''),
|
||||
'isevent' => $isevent,
|
||||
'attend' => $attend,
|
||||
'consensus' => $consensus,
|
||||
'conlabels' => $conlabels,
|
||||
'canvote' => $canvote,
|
||||
'linktitle' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
||||
'olinktitle' => (($item['owner']['xchan_addr']) ? $item['owner']['xchan_addr'] : $item['owner']['xchan_url']),
|
||||
'llink' => $item['llink'],
|
||||
@@ -426,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,
|
||||
@@ -460,12 +469,11 @@ class ThreadItem {
|
||||
'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) ? '1' : ''),
|
||||
'pinnable' => (($this->is_toplevel() && local_channel() && $item['owner_xchan'] == $observer['xchan_hash'] && $allowed_type && $item['item_private'] == 0 && $item['item_delayed'] == 0) ? '1' : ''),
|
||||
'pinme' => ($pinned ? t('Unpin from the top') : t('Pin to the top')),
|
||||
'bookmark' => (($conv->get_profile_owner() == local_channel() && local_channel() && $has_bookmarks) ? t('Save Bookmarks') : ''),
|
||||
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
|
||||
'drop' => $drop,
|
||||
'multidrop' => ((feature_enabled($conv->get_profile_owner(),'multi_delete')) ? $multidrop : ''),
|
||||
'dropdown_extras' => $dropdown_extras,
|
||||
// end toolbar buttons
|
||||
'unseen_comments' => $unseen_comments,
|
||||
@@ -488,13 +496,15 @@ class ThreadItem {
|
||||
'modal_dismiss' => t('Close'),
|
||||
'showlike' => $showlike,
|
||||
'showdislike' => $showdislike,
|
||||
'comment' => $this->get_comment_box($indent),
|
||||
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()),
|
||||
'previewing' => ($conv->is_preview() ? true : false ),
|
||||
'preview_lbl' => t('This is an unsaved preview'),
|
||||
'wait' => t('Please wait'),
|
||||
'thread_level' => $thread_level,
|
||||
'settings' => $settings,
|
||||
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? 'b64.' . base64url_encode($item['thr_parent']) : '')
|
||||
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? gen_link_id($item['thr_parent']) : ''),
|
||||
'contact_id' => (($contact) ? $contact['abook_id'] : '')
|
||||
|
||||
);
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
@@ -511,8 +521,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)) {
|
||||
@@ -532,7 +542,7 @@ class ThreadItem {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$result['private'] = $item['item_private'];
|
||||
$result['toplevel'] = ($this->is_toplevel() ? 'toplevel_item' : '');
|
||||
|
||||
@@ -547,7 +557,7 @@ class ThreadItem {
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function get_id() {
|
||||
return $this->get_data_value('id');
|
||||
}
|
||||
@@ -602,7 +612,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);
|
||||
@@ -676,7 +686,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
|
||||
@@ -780,12 +790,12 @@ class ThreadItem {
|
||||
* _ The comment box string (empty if no comment box)
|
||||
* _ false on failure
|
||||
*/
|
||||
private function get_comment_box($indent) {
|
||||
private function get_comment_box() {
|
||||
|
||||
if(!$this->is_toplevel() && !get_config('system','thread_allow')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
$comment_box = '';
|
||||
$conv = $this->get_conversation();
|
||||
|
||||
@@ -801,7 +811,7 @@ class ThreadItem {
|
||||
$arr = array('comment_buttons' => '','id' => $this->get_id());
|
||||
call_hooks('comment_buttons',$arr);
|
||||
$comment_buttons = $arr['comment_buttons'];
|
||||
|
||||
|
||||
$comment_box = replace_macros($template,array(
|
||||
'$return_path' => '',
|
||||
'$threaded' => $this->is_threaded(),
|
||||
@@ -826,14 +836,13 @@ class ThreadItem {
|
||||
'$edurl' => t('Insert Link'),
|
||||
'$edvideo' => t('Video'),
|
||||
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
|
||||
'$indent' => $indent,
|
||||
'$can_upload' => (perm_is_allowed($conv->get_profile_owner(),get_observer_hash(),'write_storage') && $conv->is_uploadable()),
|
||||
'$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false),
|
||||
'$encrypt' => t('Encrypt text'),
|
||||
'$cipher' => $conv->get_cipher(),
|
||||
'$sourceapp' => \App::$sourcename,
|
||||
'$observer' => get_observer_hash(),
|
||||
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
|
||||
'$anoncomments' => ((in_array($conv->get_mode(), ['channel', 'display', 'cards', 'articles']) && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
|
||||
'$anonname' => [ 'anonname', t('Your full name (required)') ],
|
||||
'$anonmail' => [ 'anonmail', t('Your email address (required)') ],
|
||||
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
|
||||
@@ -858,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'];
|
||||
|
||||
@@ -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
|
||||
@@ -69,15 +69,15 @@ class ThreadStream {
|
||||
case 'cards':
|
||||
$this->profile_owner = \App::$profile['profile_uid'];
|
||||
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
|
||||
$this->reload = $_SESSION['return_url'];
|
||||
//$this->reload = $_SESSION['return_url'];
|
||||
break;
|
||||
case 'articles':
|
||||
$this->profile_owner = \App::$profile['profile_uid'];
|
||||
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
|
||||
$this->reload = $_SESSION['return_url'];
|
||||
//$this->reload = $_SESSION['return_url'];
|
||||
break;
|
||||
case 'display':
|
||||
// in this mode we set profile_owner after initialisation (from conversation()) and then
|
||||
// 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(),
|
||||
|
||||
@@ -52,15 +52,21 @@ class Webfinger {
|
||||
|
||||
if(strpos($resource,'http') === 0) {
|
||||
$m = parse_url($resource);
|
||||
if($m) {
|
||||
if($m['scheme'] !== 'https') {
|
||||
return false;
|
||||
}
|
||||
self::$server = $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
|
||||
}
|
||||
else {
|
||||
|
||||
if (!$m) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isset($m['scheme']) && $m['scheme'] !== 'https') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isset($m['host'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$server = $m['host'] . ((isset($m['port'])) ? ':' . $m['port'] : '');
|
||||
|
||||
}
|
||||
elseif(strpos($resource,'tag:') === 0) {
|
||||
$arr = explode(':',$resource); // split the tag
|
||||
@@ -86,7 +92,7 @@ class Webfinger {
|
||||
/**
|
||||
* @brief fetch a webfinger resource and return a zot6 discovery url if present
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
static function zot_url($resource) {
|
||||
|
||||
@@ -106,4 +112,4 @@ class Webfinger {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ class XConfig {
|
||||
*/
|
||||
static public function Delete($xchan, $family, $key) {
|
||||
|
||||
if(x(\App::$config[$xchan][$family], $key))
|
||||
if(isset(\App::$config[$xchan][$family][$key]))
|
||||
unset(\App::$config[$xchan][$family][$key]);
|
||||
|
||||
$ret = q("DELETE FROM xconfig WHERE xchan = '%s' AND cat = '%s' AND k = '%s'",
|
||||
|
||||
@@ -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;
|
||||
@@ -88,4 +87,4 @@ class ZotURL {
|
||||
return ids_to_array($r,'hubloc_url');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use Zotlabs\Web\HTTPSig;
|
||||
|
||||
class Zotfinger {
|
||||
|
||||
static function exec($resource,$channel = null) {
|
||||
static function exec($resource, $channel = null, $verify = true, $recurse = 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,25 +29,49 @@ 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 ] );
|
||||
|
||||
logger('fetch: ' . print_r($x,true));
|
||||
|
||||
if (in_array(intval($x['return_code']), [ 404, 410 ]) && $recurse) {
|
||||
|
||||
// The resource has been deleted or doesn't exist at this location.
|
||||
// Try to find another nomadic resource for this channel and return that.
|
||||
|
||||
// First, see if there's a hubloc for this site. Fetch that record to
|
||||
// obtain the nomadic identity hash. Then use that to find any additional
|
||||
// nomadic locations.
|
||||
|
||||
$h = Activity::get_actor_hublocs($resource, 'zot6');
|
||||
if ($h) {
|
||||
// mark this location deleted
|
||||
hubloc_delete($h[0]);
|
||||
$hubs = Activity::get_actor_hublocs($h[0]['hubloc_hash']);
|
||||
if ($hubs) {
|
||||
foreach ($hubs as $hub) {
|
||||
if ($hub['hubloc_id_url'] !== $resource && !$hub['hubloc_deleted']) {
|
||||
return self::exec($hub['hubloc_id_url'], $channel, $verify);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 +84,4 @@ class Zotfinger {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Libzotdir;
|
||||
use Zotlabs\Lib\AccessList;
|
||||
|
||||
require_once 'include/acl_selectors.php';
|
||||
require_once 'include/group.php';
|
||||
|
||||
/**
|
||||
* @brief ACL selector json backend.
|
||||
@@ -46,29 +48,34 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
// '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();
|
||||
|
||||
$permitted = [];
|
||||
$sql_extra = '';
|
||||
$sql_extra2 = '';
|
||||
$sql_extra3 = '';
|
||||
$sql_extra2_xchan = '';
|
||||
$order_extra2 = '';
|
||||
|
||||
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()),
|
||||
@@ -79,40 +86,35 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
|
||||
}
|
||||
|
||||
|
||||
if($search) {
|
||||
$sql_extra = " AND pgrp.gname LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ";
|
||||
$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(
|
||||
@@ -121,7 +123,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
"name" => t('Profile','acl') . ' ' . $rv['profile_name'],
|
||||
"id" => 'vp' . $rv['id'],
|
||||
"xid" => 'vp.' . $rv['profile_guid'],
|
||||
"uids" => group_get_profile_members_xchan(local_channel(), $rv['id']),
|
||||
"uids" => AccessList::profile_members_xchan(local_channel(), $rv['id']),
|
||||
"link" => ''
|
||||
);
|
||||
}
|
||||
@@ -130,37 +132,37 @@ 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']));
|
||||
// logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(), $g['id']));
|
||||
$groups[] = array(
|
||||
"type" => "g",
|
||||
"photo" => "images/twopeople.png",
|
||||
"name" => $g['gname'],
|
||||
"id" => $g['id'],
|
||||
"xid" => $g['hash'],
|
||||
"uids" => group_get_members_xchan($g['id']),
|
||||
"uids" => AccessList::members_xchan(local_channel(), $g['id']),
|
||||
"link" => ''
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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,24 +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 abook_id as id, 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, abook_self
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE abook_channel = %d
|
||||
WHERE abook_channel = %d
|
||||
and xchan_deleted = 0
|
||||
and xchan_network IN ('zot', 'diaspora', 'friendica-over-diaspora')
|
||||
and not xchan_network IN ('rss', 'anon', 'unknown')
|
||||
$sql_extra3
|
||||
ORDER BY xchan_name ASC ",
|
||||
intval(local_channel())
|
||||
@@ -298,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, abook_self 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);
|
||||
@@ -323,7 +325,7 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$o = array(
|
||||
'start' => $start,
|
||||
'count' => $count,
|
||||
@@ -334,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(isset($g['net']) && 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',
|
||||
@@ -362,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,
|
||||
@@ -393,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;
|
||||
|
||||
@@ -21,13 +21,17 @@ class Activity extends Controller {
|
||||
if (Libzot::is_zot_request()) {
|
||||
|
||||
$item_id = argv(1);
|
||||
|
||||
if (! $item_id)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$portable_id = EMPTY_STR;
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 ";
|
||||
$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;
|
||||
|
||||
@@ -87,7 +91,7 @@ class Activity extends Controller {
|
||||
}
|
||||
|
||||
$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)
|
||||
);
|
||||
@@ -144,8 +148,8 @@ class Activity extends Controller {
|
||||
http_status_exit(403, 'Forbidden');
|
||||
|
||||
$i = ZlibActivity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection');
|
||||
if($portable_id) {
|
||||
ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id);
|
||||
if($portable_id && (! intval($items[0]['item_private']))) {
|
||||
ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id);
|
||||
}
|
||||
|
||||
if(! $i)
|
||||
@@ -170,6 +174,115 @@ class Activity extends Controller {
|
||||
|
||||
}
|
||||
|
||||
if(ActivityStreams::is_as_request()) {
|
||||
|
||||
$item_id = argv(1);
|
||||
|
||||
if (! $item_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ob_authorize = 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,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) );
|
||||
@@ -77,6 +77,7 @@ class Addons {
|
||||
} catch (\PHPGit\Exception\GitException $e) {
|
||||
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
|
||||
}
|
||||
break;
|
||||
case 'removerepo':
|
||||
if (array_key_exists('repoName', $_REQUEST)) {
|
||||
$repoName = $_REQUEST['repoName'];
|
||||
@@ -111,6 +112,7 @@ class Addons {
|
||||
} else {
|
||||
json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false));
|
||||
}
|
||||
break;
|
||||
case 'installrepo':
|
||||
if (array_key_exists('repoURL', $_REQUEST)) {
|
||||
require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
|
||||
@@ -172,6 +174,7 @@ class Addons {
|
||||
$repo = $git->probeRepo();
|
||||
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
|
||||
}
|
||||
break;
|
||||
case 'addrepo':
|
||||
if (array_key_exists('repoURL', $_REQUEST)) {
|
||||
require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
|
||||
@@ -332,7 +335,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -173,4 +173,4 @@ class Channels {
|
||||
return $o;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ namespace Zotlabs\Module\Admin;
|
||||
|
||||
|
||||
class Dbsync {
|
||||
|
||||
|
||||
|
||||
function get() {
|
||||
$o = '';
|
||||
|
||||
|
||||
if(argc() > 3 && intval(argv(3)) && argv(2) === 'mark') {
|
||||
// remove the old style config if it exists
|
||||
del_config('database', 'update_r' . intval(argv(3)));
|
||||
@@ -29,7 +29,7 @@ class Dbsync {
|
||||
if(method_exists($c,'verify')) {
|
||||
$retval = $c->verify();
|
||||
if($retval === UPDATE_FAILED) {
|
||||
$o .= sprintf( t('Verification of update %s failed. Check system logs.'), $s);
|
||||
$o .= sprintf( t('Verification of update %s failed. Check system logs.'), $s);
|
||||
}
|
||||
elseif($retval === UPDATE_SUCCESS) {
|
||||
$o .= sprintf( t('Update %s was successfully applied.'), $s);
|
||||
@@ -44,20 +44,8 @@ class Dbsync {
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Update function %s could not be found.'), $s);
|
||||
|
||||
|
||||
return $o;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// remove the old style config if it exists
|
||||
del_config('database', 'update_r' . intval(argv(3)));
|
||||
set_config('database', '_' . intval(argv(3)), 'success');
|
||||
if(intval(get_config('system','db_version')) < intval(argv(3)))
|
||||
set_config('system','db_version',intval(argv(3)));
|
||||
info( t('Update has been marked successful') . EOL);
|
||||
goaway(z_root() . '/admin/dbsync');
|
||||
}
|
||||
|
||||
if(argc() > 2 && intval(argv(2))) {
|
||||
@@ -68,7 +56,7 @@ class Dbsync {
|
||||
$c = new $cls();
|
||||
$retval = $c->run();
|
||||
if($retval === UPDATE_FAILED) {
|
||||
$o .= sprintf( t('Executing update procedure %s failed. Check system logs.'), $s);
|
||||
$o .= sprintf( t('Executing update procedure %s failed. Check system logs.'), $s);
|
||||
}
|
||||
elseif($retval === UPDATE_SUCCESS) {
|
||||
$o .= sprintf( t('Update %s was successfully applied.'), $s);
|
||||
@@ -79,10 +67,10 @@ class Dbsync {
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Update function %s could not be found.'), $s);
|
||||
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
$failed = array();
|
||||
$r = q("select * from config where cat = 'database' ");
|
||||
if(count($r)) {
|
||||
@@ -107,7 +95,7 @@ class Dbsync {
|
||||
else {
|
||||
return '<div class="generic-content-wrapper-styled"><h3>' . t('No failed updates.') . '</h3></div>';
|
||||
}
|
||||
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,52 +2,63 @@
|
||||
|
||||
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']) {
|
||||
|
||||
$expert = $_REQUEST['expert'] ?? false;
|
||||
|
||||
if(isset($_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']);
|
||||
|
||||
if(isset($_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
|
||||
|
||||
if(isset($_REQUEST['deliverhub'])) {
|
||||
|
||||
$hubq = q("SELECT * FROM outq WHERE outq_posturl = '%s'",
|
||||
dbesc($_REQUEST['deliverhub'])
|
||||
);
|
||||
|
||||
foreach ($hubq as $q) {
|
||||
LibQueue::deliver($q, true);
|
||||
}
|
||||
}
|
||||
|
||||
$r = dbq("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'),
|
||||
'$priority' => t('Priority'),
|
||||
'$desturl' => t('Destination URL'),
|
||||
'$nukehub' => t('Mark hub permanently offline'),
|
||||
'$deliverhub' => t('Retry delivery to this hub'),
|
||||
'$empty' => t('Empty queue for this hub'),
|
||||
'$lastconn' => t('Last known contact'),
|
||||
'$hasentries' => ((count($r)) ? true : false),
|
||||
'$entries' => $r,
|
||||
'$expert' => $expert
|
||||
));
|
||||
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
121
Zotlabs/Module/Admin/Queueworker.php
Normal file
121
Zotlabs/Module/Admin/Queueworker.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
class Queueworker extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
}
|
||||
|
||||
function post() {
|
||||
|
||||
check_form_security_token('form_security_token', 'queueworker');
|
||||
|
||||
$maxqueueworkers = intval($_POST['queueworker_maxworkers']);
|
||||
$maxqueueworkers = ($maxqueueworkers > 3) ? $maxqueueworkers : 4;
|
||||
set_config('queueworker', 'max_queueworkers', $maxqueueworkers);
|
||||
|
||||
$maxworkerage = intval($_POST['queueworker_max_age']);
|
||||
$maxworkerage = ($maxworkerage >= 120) ? $maxworkerage : 300;
|
||||
set_config('queueworker', 'queueworker_max_age', $maxworkerage);
|
||||
|
||||
$queueworkersleep = intval($_POST['queue_worker_sleep']);
|
||||
$queueworkersleep = ($queueworkersleep > 100) ? $queueworkersleep : 100;
|
||||
set_config('queueworker', 'queue_worker_sleep', $queueworkersleep);
|
||||
|
||||
$auto_queue_worker_sleep = intval($_POST['auto_queue_worker_sleep']);
|
||||
set_config('queueworker', 'auto_queue_worker_sleep', $auto_queue_worker_sleep);
|
||||
|
||||
goaway(z_root() . '/admin/queueworker');
|
||||
}
|
||||
|
||||
function get() {
|
||||
|
||||
$content = "<H1>Queue Status</H1>\n";
|
||||
|
||||
$r = q('select count(*) as total from workerq');
|
||||
|
||||
$content .= "<H4>There are " . $r[0]['total'] . " queue items to be processed.</H4>";
|
||||
|
||||
$r = dbq("select count(distinct workerq_reservationid) as qworkers from workerq where workerq_reservationid is not null");
|
||||
|
||||
$content .= "<H4>Active workers: " . $r[0]['qworkers'] . "</H4>";
|
||||
|
||||
$r = dbq("select workerq_cmd, count(*) as total from workerq where true group by workerq_cmd");
|
||||
|
||||
if ($r) {
|
||||
$content .= "<H4>Work items</H4>";
|
||||
foreach($r as $rr) {
|
||||
$content .= $rr['workerq_cmd'] . ': ' . $rr['total'] . '<br>';
|
||||
}
|
||||
}
|
||||
|
||||
$maxqueueworkers = get_config('queueworker', 'max_queueworkers', 4);
|
||||
$maxqueueworkers = ($maxqueueworkers > 3) ? $maxqueueworkers : 4;
|
||||
|
||||
$sc = '';
|
||||
|
||||
$sc .= replace_macros(get_markup_template('field_input.tpl'), [
|
||||
'$field' => [
|
||||
'queueworker_maxworkers',
|
||||
t('Max queueworker threads'),
|
||||
$maxqueueworkers,
|
||||
t('Minimum 4, default 4')
|
||||
]
|
||||
]);
|
||||
|
||||
$workermaxage = get_config('queueworker', 'queueworker_max_age');
|
||||
$workermaxage = ($workermaxage >= 120) ? $workermaxage : 300;
|
||||
|
||||
$sc .= replace_macros(get_markup_template('field_input.tpl'), [
|
||||
'$field' => [
|
||||
'queueworker_max_age',
|
||||
t('Assume workers dead after'),
|
||||
$workermaxage,
|
||||
t('Minimum 120, default 300 seconds')
|
||||
]
|
||||
]);
|
||||
|
||||
$queueworkersleep = get_config('queueworker', 'queue_worker_sleep');
|
||||
$queueworkersleep = ($queueworkersleep > 100) ? $queueworkersleep : 100;
|
||||
|
||||
$auto_queue_worker_sleep = get_config('queueworker', 'auto_queue_worker_sleep', 0);
|
||||
|
||||
$sc .= replace_macros(get_markup_template('field_input.tpl'), [
|
||||
'$field' => [
|
||||
'queue_worker_sleep',
|
||||
t('Pause before starting next task'),
|
||||
$queueworkersleep,
|
||||
t('Minimum 100, default 100 microseconds'),
|
||||
'',
|
||||
(($auto_queue_worker_sleep) ? 'disabled' : '')
|
||||
]
|
||||
]);
|
||||
|
||||
$sc .= replace_macros(get_markup_template('field_checkbox.tpl'), [
|
||||
'$field' => [
|
||||
'auto_queue_worker_sleep',
|
||||
t('Automatically adjust pause before starting next task'),
|
||||
$auto_queue_worker_sleep,
|
||||
]
|
||||
]);
|
||||
|
||||
$tpl = get_markup_template('settings_addon.tpl');
|
||||
$content .= replace_macros($tpl, [
|
||||
'$action_url' => 'admin/queueworker',
|
||||
'$form_security_token' => get_form_security_token('queueworker'),
|
||||
'$title' => t('Queueworker Settings'),
|
||||
'$content' => $sc,
|
||||
'$baseurl' => z_root(),
|
||||
'$submit' => t('Save')
|
||||
]
|
||||
);
|
||||
|
||||
return $content;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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,13 +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']) : '');
|
||||
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
|
||||
//$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 . EOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
// <-hilmar]
|
||||
|
||||
set_config('system', 'feed_contacts', $feed_contacts);
|
||||
set_config('system', 'delivery_interval', $delivery_interval);
|
||||
set_config('system', 'delivery_batch_count', $delivery_batch_count);
|
||||
@@ -93,6 +149,10 @@ 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);
|
||||
@@ -123,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);
|
||||
@@ -142,7 +205,7 @@ class Site {
|
||||
set_config('system','disable_discover_tab', $disable_discover_tab);
|
||||
set_config('system','site_firehose', $site_firehose);
|
||||
set_config('system','open_pubstream', $open_pubstream);
|
||||
set_config('system','force_queue_threshold', $force_queue);
|
||||
//set_config('system','force_queue_threshold', $force_queue);
|
||||
if ($global_directory == '') {
|
||||
del_config('system', 'directory_submit_url');
|
||||
} else {
|
||||
@@ -151,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);
|
||||
@@ -254,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(
|
||||
@@ -271,18 +339,78 @@ class Site {
|
||||
// now invert the logic for the setting.
|
||||
$discover_tab = (1 - $discover_tab);
|
||||
|
||||
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
|
||||
$default_role = get_config('system','default_permissions_role','social');
|
||||
$perm_roles = \Zotlabs\Access\PermissionRoles::channel_roles();
|
||||
$default_role = get_config('system', 'default_permissions_role', 'personal');
|
||||
|
||||
if (!in_array($default_role, array_keys($perm_roles))) {
|
||||
$default_role = 'personal';
|
||||
}
|
||||
|
||||
$role = array('permissions_role' , t('Default permission role for new accounts'), $default_role, t('This role will be used for the first channel created after registration.'),$perm_roles);
|
||||
|
||||
|
||||
$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'),
|
||||
@@ -299,25 +427,91 @@ 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.')),
|
||||
'$open_pubstream' => array('open_pubstream', t('Allow anybody on the internet to access the Public streams'), get_config('system','open_pubstream',1), t('Disable to require authentication before viewing. Warning: this content is unmoderated.')),
|
||||
'$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('Enable public stream'), $discover_tab, t('Enable the public stream. Warning: this content is unmoderated')),
|
||||
'$site_firehose' => array('site_firehose', t('Site only public stream'), get_config('system','site_firehose'), t('Restrict the public stream to content originating at this site')),
|
||||
'$open_pubstream' => array('open_pubstream', t('Allow anybody on the internet to access the public streams'), get_config('system','open_pubstream',1), t('Disable to require authentication before viewing')),
|
||||
'$incl' => array('pub_incl',t('Only import Public stream posts with this text'), get_config('system','pubstream_incl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')),
|
||||
'$excl' => array('pub_excl',t('Do not import Public stream posts with this text'), get_config('system','pubstream_excl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')),
|
||||
|
||||
@@ -331,26 +525,197 @@ 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).")),
|
||||
'$delivery_interval' => array('delivery_interval', t("Delivery interval"), (x(get_config('system','delivery_interval'))?get_config('system','delivery_interval'):2), t("Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.")),
|
||||
'$delivery_batch_count' => array('delivery_batch_count', t('Deliveries per process'),(x(get_config('system','delivery_batch_count'))?get_config('system','delivery_batch_count'):1), t("Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.")),
|
||||
'$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.")),
|
||||
//'$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")),
|
||||
'$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 ;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -44,17 +44,14 @@ class Affinity extends \Zotlabs\Web\Controller {
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
$desc = t('This app presents a slider control in your connection editor and also on your network page. The slider represents your degree of friendship (affinity) with each connection. It allows you to zoom in or out and display conversations from only your closest friends or everybody in your stream.');
|
||||
if(! Apps::system_app_installed(local_channel(),'Affinity Tool')) {
|
||||
if(! Apps::system_app_installed(local_channel(), 'Affinity Tool')) {
|
||||
//Do not display any associated widgets at this point
|
||||
App::$pdl = '';
|
||||
|
||||
$o = '<b>' . t('Affinity Tool App') . ' (' . t('Not Installed') . '):</b><br>';
|
||||
$o .= $desc;
|
||||
return $o;
|
||||
$papp = Apps::get_papp('Affinity Tool');
|
||||
return Apps::app_render($papp, 'module');
|
||||
}
|
||||
|
||||
$text = t('The numbers below represent the minimum and maximum slider default positions for your network/stream page as a percentage.');
|
||||
$text = t('The numbers below represent the minimum and maximum slider default positions for your network/stream page as a percentage.');
|
||||
|
||||
$content = '<div class="section-content-info-wrapper">' . $text . '</div>';
|
||||
|
||||
|
||||
103
Zotlabs/Module/Album.php
Normal file
103
Zotlabs/Module/Album.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
require_once('include/security.php');
|
||||
require_once('include/attach.php');
|
||||
require_once('include/photo/photo_driver.php');
|
||||
require_once('include/photos.php');
|
||||
|
||||
|
||||
class Album extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
if (ActivityStreams::is_as_request()) {
|
||||
$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);
|
||||
}
|
||||
elseif (Config::get('system', 'require_authenticated_fetch', false)) {
|
||||
http_status_exit(403, 'Permission denied');
|
||||
}
|
||||
|
||||
$observer_xchan = get_observer_hash();
|
||||
$allowed = false;
|
||||
|
||||
$bear = Activity::token_from_request();
|
||||
if ($bear) {
|
||||
logger('bear: ' . $bear, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
$channel = null;
|
||||
|
||||
if (argc() > 1) {
|
||||
$channel = channelx_by_nick(argv(1));
|
||||
}
|
||||
if (!$channel) {
|
||||
http_status_exit(404, 'Not found.');
|
||||
}
|
||||
|
||||
$sql_extra = permissions_sql($channel['channel_id'], $observer_xchan);
|
||||
|
||||
if (argc() > 2) {
|
||||
$folder = argv(2);
|
||||
$r = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d $sql_extra limit 1",
|
||||
dbesc($folder),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
$allowed = (($r) ? attach_can_view($channel['channel_id'], $observer_xchan, $r[0]['hash'] /*,$bear */) : false);
|
||||
}
|
||||
else {
|
||||
$folder = EMPTY_STR;
|
||||
$allowed = perm_is_allowed($channel['channel_id'], $observer_xchan, 'view_storage');
|
||||
}
|
||||
|
||||
if (!$allowed) {
|
||||
http_status_exit(403, 'Permission denied.');
|
||||
}
|
||||
|
||||
$x = q("select * from attach where folder = '%s' and uid = %d $sql_extra",
|
||||
dbesc($folder),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
$contents = [];
|
||||
|
||||
if ($x) {
|
||||
foreach ($x as $xv) {
|
||||
if (intval($xv['is_dir'])) {
|
||||
continue;
|
||||
}
|
||||
if (!attach_can_view($channel['channel_id'], $observer_xchan, $xv['hash'] /*,$bear*/)) {
|
||||
continue;
|
||||
}
|
||||
if (intval($xv['is_photo'])) {
|
||||
$contents[] = z_root() . '/photo/' . $xv['hash'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$obj = Activity::encode_simple_collection($contents, App::$query_string, 'OrderedCollection', count($contents));
|
||||
as_return_and_die($obj, $channel);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<?php /** @file */
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
//require_once('include/apps.php');
|
||||
|
||||
use \Zotlabs\Lib as Zlib;
|
||||
use App;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
class Appman extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
if($_POST['url']) {
|
||||
|
||||
if(isset($_POST['url']) && $_POST['url']) {
|
||||
$arr = array(
|
||||
'uid' => intval($_REQUEST['uid']),
|
||||
'url' => escape_tags($_REQUEST['url']),
|
||||
@@ -32,70 +32,136 @@ class Appman extends \Zotlabs\Web\Controller {
|
||||
'sig' => escape_tags($_REQUEST['sig']),
|
||||
'categories' => escape_tags($_REQUEST['categories'])
|
||||
);
|
||||
|
||||
$_REQUEST['appid'] = Zlib\Apps::app_install(local_channel(),$arr);
|
||||
|
||||
if(Zlib\Apps::app_installed(local_channel(),$arr))
|
||||
|
||||
$_REQUEST['appid'] = Apps::app_install(local_channel(),$arr);
|
||||
|
||||
if(Apps::app_installed(local_channel(),$arr))
|
||||
info( t('App installed.') . EOL);
|
||||
|
||||
goaway(z_root() . '/apps');
|
||||
return; //not reached
|
||||
}
|
||||
|
||||
|
||||
$papp = Zlib\Apps::app_decode($_POST['papp']);
|
||||
|
||||
|
||||
|
||||
$papp = Apps::app_decode($_POST['papp']);
|
||||
|
||||
if(! is_array($papp)) {
|
||||
notice( t('Malformed app.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if($_POST['install']) {
|
||||
Zlib\Apps::app_install(local_channel(),$papp);
|
||||
if(Zlib\Apps::app_installed(local_channel(),$papp))
|
||||
|
||||
if(isset($_POST['install']) && $_POST['install']) {
|
||||
Apps::app_install(local_channel(),$papp);
|
||||
if(Apps::app_installed(local_channel(),$papp))
|
||||
info( t('App installed.') . EOL);
|
||||
}
|
||||
|
||||
if($_POST['delete']) {
|
||||
Zlib\Apps::app_destroy(local_channel(),$papp);
|
||||
|
||||
$sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1",
|
||||
intval(local_channel()),
|
||||
dbesc($papp['guid'])
|
||||
);
|
||||
|
||||
if (!$sync) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (intval($sync[0]['app_system'])) {
|
||||
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
|
||||
}
|
||||
else {
|
||||
Libsync::build_sync_packet(local_channel(), ['app' => $sync]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($_POST['edit']) {
|
||||
if(isset($_POST['delete']) && $_POST['delete']) {
|
||||
|
||||
// Fetch the app for sync before it is deleted (if it is deletable))
|
||||
$sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1",
|
||||
intval(local_channel()),
|
||||
dbesc($papp['guid'])
|
||||
);
|
||||
|
||||
if (!$sync) {
|
||||
return;
|
||||
}
|
||||
|
||||
Apps::app_destroy(local_channel(), $papp);
|
||||
|
||||
// Now flag it deleted
|
||||
$sync[0]['app_deleted'] = 1;
|
||||
|
||||
if (intval($sync[0]['app_system'])) {
|
||||
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
|
||||
}
|
||||
else {
|
||||
Libsync::build_sync_packet(local_channel(), ['app' => $sync]);
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_POST['edit']) && $_POST['edit']) {
|
||||
return;
|
||||
}
|
||||
|
||||
if($_POST['feature']) {
|
||||
Zlib\Apps::app_feature(local_channel(), $papp, $_POST['feature']);
|
||||
if(isset($_POST['feature']) && $_POST['feature']) {
|
||||
Apps::app_feature(local_channel(), $papp, $_POST['feature']);
|
||||
|
||||
$sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1",
|
||||
intval(local_channel()),
|
||||
dbesc($papp['guid'])
|
||||
);
|
||||
|
||||
if (intval($sync[0]['app_system'])) {
|
||||
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
|
||||
}
|
||||
else {
|
||||
Libsync::build_sync_packet(local_channel(), ['app' => $sync]);
|
||||
}
|
||||
}
|
||||
|
||||
if($_POST['pin']) {
|
||||
Zlib\Apps::app_feature(local_channel(), $papp, $_POST['pin']);
|
||||
if(isset($_POST['pin']) && $_POST['pin']) {
|
||||
Apps::app_feature(local_channel(), $papp, $_POST['pin']);
|
||||
|
||||
$sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1",
|
||||
intval(local_channel()),
|
||||
dbesc($papp['guid'])
|
||||
);
|
||||
|
||||
if (intval($sync[0]['app_system'])) {
|
||||
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
|
||||
}
|
||||
else {
|
||||
Libsync::build_sync_packet(local_channel(), ['app' => $sync]);
|
||||
}
|
||||
}
|
||||
|
||||
if($_SESSION['return_url'])
|
||||
if(isset($_POST['aj']) && $_POST['aj']) {
|
||||
killme();
|
||||
}
|
||||
|
||||
if($_SESSION['return_url'])
|
||||
goaway(z_root() . '/' . $_SESSION['return_url']);
|
||||
|
||||
goaway(z_root() . '/apps');
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
|
||||
if(! local_channel()) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
$channel = App::get_channel();
|
||||
|
||||
if(argc() > 3) {
|
||||
if(argv(2) === 'moveup') {
|
||||
Zlib\Apps::moveup(local_channel(),argv(1),argv(3));
|
||||
Apps::moveup(local_channel(),argv(1),argv(3));
|
||||
}
|
||||
if(argv(2) === 'movedown') {
|
||||
Zlib\Apps::movedown(local_channel(),argv(1),argv(3));
|
||||
Apps::movedown(local_channel(),argv(1),argv(3));
|
||||
}
|
||||
goaway(z_root() . '/apporder');
|
||||
}
|
||||
@@ -105,7 +171,7 @@ class Appman extends \Zotlabs\Web\Controller {
|
||||
|
||||
$app = null;
|
||||
$embed = null;
|
||||
if($_REQUEST['appid']) {
|
||||
if(isset($_REQUEST['appid']) && $_REQUEST['appid']) {
|
||||
$r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
|
||||
dbesc($_REQUEST['appid']),
|
||||
dbesc(local_channel())
|
||||
@@ -129,32 +195,30 @@ class Appman extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$embed = array('embed', t('Embed code'), Zlib\Apps::app_encode($app,true),'', 'onclick="this.select();"');
|
||||
|
||||
$embed = array('embed', t('Embed code'), Apps::app_encode($app,true),'', 'onclick="this.select();"');
|
||||
|
||||
}
|
||||
|
||||
|
||||
return replace_macros(get_markup_template('app_create.tpl'), array(
|
||||
|
||||
'$banner' => (($app) ? t('Edit App') : t('Create App')),
|
||||
'$app' => $app,
|
||||
'$guid' => (($app) ? $app['app_id'] : ''),
|
||||
'$author' => (($app) ? $app['app_author'] : $channel['channel_hash']),
|
||||
'$addr' => (($app) ? $app['app_addr'] : $channel['xchan_addr']),
|
||||
'$name' => array('name', t('Name of app'),(($app) ? $app['app_name'] : ''), t('Required')),
|
||||
'$url' => array('url', t('Location (URL) of app'),(($app) ? $app['app_url'] : ''), t('Required')),
|
||||
'$desc' => array('desc', t('Description'),(($app) ? $app['app_desc'] : ''), ''),
|
||||
'$photo' => array('photo', t('Photo icon URL'),(($app) ? $app['app_photo'] : ''), t('80 x 80 pixels - optional')),
|
||||
'$categories' => array('categories',t('Categories (optional, comma separated list)'),(($app) ? $app['categories'] : ''),''),
|
||||
'$version' => array('version', t('Version ID'),(($app) ? $app['app_version'] : ''), ''),
|
||||
'$price' => array('price', t('Price of app'),(($app) ? $app['app_price'] : ''), ''),
|
||||
'$page' => array('page', t('Location (URL) to purchase app'),(($app) ? $app['app_page'] : ''), ''),
|
||||
'$system' => (($app) ? intval($app['app_system']) : 0),
|
||||
'$plugin' => (($app) ? $app['app_plugin'] : ''),
|
||||
'$requires' => (($app) ? $app['app_requires'] : ''),
|
||||
'$guid' => $app['app_id'] ?? '',
|
||||
'$author' => $app['app_author'] ?? $channel['channel_hash'],
|
||||
'$addr' => $app['app_addr'] ?? $channel['xchan_addr'],
|
||||
'$name' => array('name', t('Name of app'), $app['app_name'] ?? '', t('Required')),
|
||||
'$url' => array('url', t('Location (URL) of app'), $app['app_url'] ?? '', t('Required')),
|
||||
'$desc' => array('desc', t('Description'), $app['app_desc'] ?? '', ''),
|
||||
'$photo' => array('photo', t('Photo icon URL'),$app['app_photo'] ?? '', t('80 x 80 pixels - optional')),
|
||||
'$categories' => array('categories',t('Categories (optional, comma separated list)'), $app['categories'] ?? '',''),
|
||||
'$version' => array('version', t('Version ID'), $app['app_version'] ?? '', ''),
|
||||
'$price' => array('price', t('Price of app'), $app['app_price'] ?? '', ''),
|
||||
'$page' => array('page', t('Location (URL) to purchase app'), $app['app_page'] ?? '', ''),
|
||||
'$system' => $app['app_system'] ?? 0,
|
||||
'$plugin' => $app['app_plugin'] ?? '',
|
||||
'$requires' => $app['app_requires'] ?? '',
|
||||
'$embed' => $embed,
|
||||
'$submit' => t('Submit')
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ class Apps extends \Zotlabs\Web\Controller {
|
||||
function get() {
|
||||
|
||||
nav_set_selected('Apps');
|
||||
|
||||
|
||||
if(argc() == 2 && argv(1) == 'edit')
|
||||
$mode = 'edit';
|
||||
else
|
||||
@@ -18,9 +18,10 @@ class Apps extends \Zotlabs\Web\Controller {
|
||||
$available = ((argc() == 2 && argv(1) === 'available') ? true : false);
|
||||
|
||||
$_SESSION['return_url'] = \App::$query_string;
|
||||
|
||||
$apps = array();
|
||||
|
||||
|
||||
$apps = [];
|
||||
$cat = [];
|
||||
|
||||
if(local_channel()) {
|
||||
Zlib\Apps::import_system_apps();
|
||||
$syslist = array();
|
||||
@@ -37,9 +38,9 @@ class Apps extends \Zotlabs\Web\Controller {
|
||||
$syslist = Zlib\Apps::get_system_apps(true);
|
||||
|
||||
usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
|
||||
|
||||
|
||||
// logger('apps: ' . print_r($syslist,true));
|
||||
|
||||
|
||||
foreach($syslist as $app) {
|
||||
$apps[] = Zlib\Apps::app_render($app,(($available) ? 'install' : $mode));
|
||||
}
|
||||
@@ -53,7 +54,7 @@ class Apps extends \Zotlabs\Web\Controller {
|
||||
'$manage' => (($available) ? '' : t('Manage Apps')),
|
||||
'$create' => (($mode == 'edit') ? t('Create Custom App') : '')
|
||||
));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user