mirror of
https://git.sekbaer.de/Friendica/friendica.git
synced 2025-06-07 15:54:26 +02:00
Compare commits
1344 commits
Author | SHA1 | Date | |
---|---|---|---|
|
e3a00dfa8d | ||
|
8083fb6f8e | ||
|
bec89a822a | ||
|
f1143105d2 | ||
|
ab3e54f0e1 | ||
|
1723417f43 | ||
|
fce04bfa5c | ||
|
02f6bb1256 | ||
|
2e9e5715cc | ||
|
f6333d38e1 | ||
|
69dd232ee8 | ||
|
3e8080d67d | ||
|
f32cb5c0dc | ||
|
dfe86ee677 | ||
|
3e3f49219d | ||
|
497798b455 | ||
|
441584b0d1 | ||
|
130ae2d773 | ||
|
9a1470d2a4 | ||
|
3883bdf96f | ||
|
544b926c9e | ||
|
3c4ae5a124 | ||
|
167ac1ec0f | ||
|
c1620f9a62 | ||
|
f2ee3602ac | ||
|
7ca99aa194 | ||
|
3bd6335fa6 | ||
|
3def76649b | ||
|
2e701df21a | ||
|
1e818053f6 | ||
|
8be3c2bc99 | ||
|
dc0dee77d0 | ||
|
5c6b7d9293 | ||
|
592eede9cd | ||
|
69ee39b725 | ||
|
415e7b5f8b | ||
|
5e1755dc8f | ||
|
2335af9bf2 | ||
|
0db3d4a70f | ||
|
6e84c0ade7 | ||
|
423ab06010 | ||
|
978dda0b4e | ||
|
70e57b54c3 | ||
|
da413283da | ||
|
8e0a3d00bb | ||
|
35ae7278f7 | ||
|
3af5caa950 | ||
|
78d28ae24b | ||
|
f49172e9c0 | ||
|
6cad772abd | ||
|
777fc8615c | ||
|
0078423b48 | ||
|
638496e553 | ||
|
7b7d542c8f | ||
|
6b71010de6 | ||
|
7f55714296 | ||
|
44c8cd118c | ||
|
075e9eaaa9 | ||
|
367f7bd377 | ||
|
5cf2b7d7bd | ||
|
0165e22064 | ||
|
58ac3fbb29 | ||
|
33398298d5 | ||
|
a39850871e | ||
|
88dcd755a9 | ||
|
5f7de9d028 | ||
|
08b60c2558 | ||
|
8b40d65e6c | ||
|
2475095da0 | ||
|
292b55ede6 | ||
|
0599801b37 | ||
|
93a171765a | ||
|
20d9855101 | ||
|
f97b01a69a | ||
|
e2a2cf5d6e | ||
|
6a058793f0 | ||
|
d88119139f | ||
|
3481c3ad15 | ||
|
02fae146e6 | ||
|
b2bbcc4965 | ||
|
ea172010f8 | ||
|
054a280d33 | ||
|
3a257b6172 | ||
|
09668d5e56 | ||
|
2fd374caeb | ||
|
a4d4e199c1 | ||
|
dfa1f52ad6 | ||
|
19d7d2f345 | ||
|
ed5de437be | ||
|
63558f92eb | ||
|
4d879781c2 | ||
|
b38c754446 | ||
|
2b00d1b2d0 | ||
|
db1f7164b8 | ||
|
b782ff6e22 | ||
|
0f7c739470 | ||
|
024b136cdd | ||
|
38e89b152c | ||
|
351bc94d06 | ||
|
581dec10eb | ||
|
a784428f85 | ||
|
d1b8f31fe8 | ||
|
42b411788a | ||
|
4b9a674659 | ||
|
baaec75bfc | ||
|
362b223c5e | ||
|
f5eee2c334 | ||
|
2ccb62bbd8 | ||
|
2e50e93872 | ||
|
d6b072477d | ||
|
ec16994738 | ||
|
c6c6640b81 | ||
|
7b39b3b9c0 | ||
|
03cfa2d066 | ||
|
c92d239091 | ||
|
b222aa0c48 | ||
|
892fa595da | ||
|
5969576585 | ||
|
50c720688b | ||
|
a20828f618 | ||
|
01296e98f9 | ||
|
ffb621f0e4 | ||
|
403b0672e6 | ||
|
102db4fca0 | ||
|
f840d1f582 | ||
|
09c6061810 | ||
|
85e5dfc8cf | ||
|
cd73f6a27b | ||
|
cd3d412a59 | ||
|
7dc681d18c | ||
|
37d324e63b | ||
|
fa58d8b11a | ||
|
cc4ff9584f | ||
|
e7bd6e7663 | ||
|
32b657b793 | ||
|
60ad014a6e | ||
|
d410758cdd | ||
|
c0065a68b3 | ||
|
fc1d8e92f3 | ||
|
af29baf11e | ||
|
6b36d3e87f | ||
|
8fb2fae841 | ||
|
252b3980d0 | ||
|
0cec451497 | ||
|
0b41eb1528 | ||
|
77269f52eb | ||
|
65624e2c19 | ||
|
2e672414b3 | ||
|
f1abd57356 | ||
|
2a7d329c52 | ||
|
c436f5249b | ||
|
7531a2fb36 | ||
|
531a47f7cb | ||
|
3ea20e9eee | ||
|
86ebbecff5 | ||
|
83f561ea49 | ||
|
7bfd42ac55 | ||
|
8ebbe8141a | ||
|
39439fe26b | ||
|
ff3c4046e0 | ||
|
f08aef86f1 | ||
|
2a7ebc860c | ||
|
a34a93c0b9 | ||
|
507897eec1 | ||
|
6cab9c010d | ||
|
43f67dd2a2 | ||
|
fb8cc06ce2 | ||
|
5c1b5bae61 | ||
|
584e7e05b0 | ||
|
e4cb372760 | ||
|
27e474c83c | ||
|
a9b36f55c9 | ||
|
a9f02bfef5 | ||
|
88929bb307 | ||
|
20a1d22620 | ||
|
f0273a618c | ||
|
76c3eeb96e | ||
|
90db7d2e65 | ||
|
cf56aa3a64 | ||
|
fdadf646c4 | ||
|
dde6722c5b | ||
|
47e4bad151 | ||
|
6f159e69be | ||
|
9822dd25d8 | ||
|
fcb8892e2f | ||
|
1ddd5674e1 | ||
|
59359f7d9d | ||
|
ac8ca35b2b | ||
|
2276bdcd7e | ||
|
4a1a1d3ca3 | ||
|
84148663e2 | ||
|
d48e491144 | ||
|
671eff8884 | ||
|
674b6c55de | ||
|
77e785dd7d | ||
|
2de7034e16 | ||
|
0aa350f1c8 | ||
|
5f70ae9c1e | ||
|
c6fbacd3e8 | ||
|
3121a256e2 | ||
|
353ad039c8 | ||
|
9c6f5f222d | ||
|
9aeb68231d | ||
|
abe35732d8 | ||
|
68b604812c | ||
|
d34861ee96 | ||
|
9cf0ce0b99 | ||
|
9e3b0b3c40 | ||
|
04818781a7 | ||
|
2c0c87339e | ||
|
8ba652818f | ||
|
b632b1d84e | ||
|
2c87e7e102 | ||
|
71bef03316 | ||
|
bdfc87ab0d | ||
|
cd00a8950f | ||
|
2a722b16aa | ||
|
10e4f4bf36 | ||
|
4d96875656 | ||
|
0427812269 | ||
|
b999472ddb | ||
|
bb6a4a3acd | ||
|
2dfd7c83cf | ||
|
a63babc658 | ||
|
441846cfbd | ||
|
7e66b35b46 | ||
|
e1eb6fff83 | ||
|
7ce6afd151 | ||
|
9ea4f591c7 | ||
|
268d564930 | ||
|
a50383836d | ||
|
bf530a00d7 | ||
|
aeaa488d1b | ||
|
6b7dd7bd12 | ||
|
8620b59dcc | ||
|
c1184698ee | ||
|
64d85ad86a | ||
|
24cbfd0953 | ||
|
9e4a69150c | ||
|
9261b5262c | ||
|
d990026fb8 | ||
|
b2f50301f4 | ||
|
ecfb82693d | ||
|
f504c9d60a | ||
|
4883035f89 | ||
|
3b5ad05e47 | ||
|
767ac778c9 | ||
|
38343ee417 | ||
|
eb37bcaa74 | ||
|
3975491887 | ||
|
77831aaf49 | ||
|
dc3dcb4a36 | ||
|
e9dae569cc | ||
|
6b7dfa34e9 | ||
|
4ebabd5997 | ||
|
0b162b4429 | ||
|
af17e33d4e | ||
|
fc8946cf02 | ||
|
1ced848827 | ||
|
fb9a20feaa | ||
|
c72d2d44c6 | ||
|
980beb4b1c | ||
|
354d13167e | ||
|
afcc5a9205 | ||
|
3bc3f5fe4d | ||
|
b6312f1dfc | ||
|
f64660ec25 | ||
|
1820bfc2b3 | ||
|
21c2c1559b | ||
|
35d95b991b | ||
|
8e7676bfd8 | ||
|
fead446624 | ||
|
f6ac16d513 | ||
|
cea8cf1f6c | ||
|
c1653877fb | ||
|
459ad05137 | ||
|
16cbaf890a | ||
|
2254bee74d | ||
|
83f64b4931 | ||
|
f6d5cd039e | ||
|
ca3d98b9f5 | ||
|
4546a4af51 | ||
|
82ea62ba7c | ||
|
f3a8bcff11 | ||
|
f98aee686f | ||
|
c66588cc2a | ||
|
27a7735c65 | ||
|
3d3e34865b | ||
|
a94bead5f6 | ||
|
4f3349f6db | ||
|
7366e70a56 | ||
|
efd3cb30d1 | ||
|
94b47ae4d1 | ||
|
3ecae98f86 | ||
|
c3f2bfaef3 | ||
|
02f693488f | ||
|
48372faec6 | ||
|
c746017cda | ||
|
1bc2cfa0a1 | ||
|
0025467500 | ||
|
d5f5ebbd8a | ||
|
62d27de3b0 | ||
|
81b6ed9fc2 | ||
|
a6ab7dd6f1 | ||
|
0b3915322b | ||
|
ce4e77fbb6 | ||
|
b9a401454d | ||
|
aff117284b | ||
|
b3ef18bed7 | ||
|
85fceaa16e | ||
|
ca3edb866a | ||
|
02976067c3 | ||
|
d4ba28a997 | ||
|
4bdd5f6bbe | ||
|
7260f29292 | ||
|
674ad96b69 | ||
|
134d85b9c1 | ||
|
3295b9055f | ||
|
abc38bec75 | ||
|
cfb9a3a41c | ||
|
23f16df112 | ||
|
caef97752a | ||
|
6e70ad1f0e | ||
|
912345d469 | ||
|
22ea08b81b | ||
|
37f09cd0e3 | ||
|
5f5a98135d | ||
|
b2da52fa3b | ||
|
dd6f479401 | ||
|
8174c36b57 | ||
|
849cc01e2b | ||
|
ed467e6eae | ||
|
7d792600b4 | ||
|
4d9b91ac96 | ||
|
98445a14e4 | ||
|
2d2fad981b | ||
|
17207dbb67 | ||
|
ff342ce5cc | ||
|
eeab1144cf | ||
|
5aeddcd5e3 | ||
|
6b0a2d1eb9 | ||
|
f3af47ca5b | ||
|
3c3c69dfd8 | ||
|
23ce65c5d0 | ||
|
18369854b7 | ||
|
7298ad29c1 | ||
|
f4624b0591 | ||
|
b1f4184d96 | ||
|
742cde89e6 | ||
|
5e00120465 | ||
|
3439d05fbf | ||
|
aabf9a8b01 | ||
|
649ddf7ab9 | ||
|
c8dd900635 | ||
|
5beeda612a | ||
|
1ea2df569e | ||
|
e5416ca4a9 | ||
|
10f5f0358a | ||
|
6cd92da46c | ||
|
2ceded19c4 | ||
|
bd65c4d1a8 | ||
|
87e3d8c790 | ||
|
5646a8283d | ||
|
7812a6d8fe | ||
|
006ff7be8f | ||
|
c7b1961d02 | ||
|
c6ee2c461c | ||
|
2cea3203b5 | ||
|
d71264993d | ||
|
98f1ae444c | ||
|
47db6de393 | ||
|
a2e9247936 | ||
|
91a145106d | ||
|
58d1d4c1fb | ||
|
703024d9b9 | ||
|
d086a982f9 | ||
|
9e7a527327 | ||
|
c77c6140fd | ||
|
a378a85c04 | ||
|
7f8ac7aaea | ||
|
22b8be6a8c | ||
|
74bfa7721d | ||
|
732c32cb0e | ||
|
9f7774faab | ||
|
62f87c13ea | ||
|
f634ec4758 | ||
|
0837ad647a | ||
|
70a6c6ed01 | ||
|
d9a2d676d2 | ||
|
673fc71c21 | ||
|
f3ccd198a4 | ||
|
b9a191f6d8 | ||
|
715248d6a2 | ||
|
5b28b3d28f | ||
|
4cbee618d6 | ||
|
16fb80be1f | ||
|
0c406a3696 | ||
|
7e199f034b | ||
|
2a02f58886 | ||
|
2e660f44f2 | ||
|
9e6f77c4b1 | ||
|
df17de7ea7 | ||
|
23f66d1708 | ||
|
01f852a87c | ||
|
827541ed86 | ||
|
25bb9b12c1 | ||
|
86516d8b28 | ||
|
a006aba9d4 | ||
|
d8470b68df | ||
|
4e9276e1c9 | ||
|
8cb48ded4d | ||
|
b0e3f1f64d | ||
|
edbf86449d | ||
|
a80bf0ddf1 | ||
|
af1894504d | ||
|
4c71ac643d | ||
|
9f086c40e4 | ||
|
e596a0b624 | ||
|
0cf1ef397b | ||
|
5497fd3559 | ||
|
31f62b807a | ||
|
fda70f3fe3 | ||
|
a678f41ca7 | ||
|
a276337752 | ||
|
105f848dd7 | ||
|
ecbd0423da | ||
|
a8249be928 | ||
|
61fa36b227 | ||
|
db37a93efa | ||
|
776781e522 | ||
|
c50827a803 | ||
|
795873b911 | ||
|
7bbefae3e6 | ||
|
b5bff3f758 | ||
|
f3c5855fc1 | ||
|
95d3ce5441 | ||
|
773f654e99 | ||
|
afba22e2cc | ||
|
7b5b9c164e | ||
|
2abc7b4986 | ||
|
b84eb33ae2 | ||
|
4ea648475f | ||
|
04df082d4e | ||
|
bc6145c684 | ||
|
655df1fd8e | ||
|
9c002a1aa2 | ||
|
d82483f342 | ||
|
9d506071c8 | ||
|
5ad82bce23 | ||
|
c4469cb624 | ||
|
7b0e31714f | ||
|
5504fdcd06 | ||
|
91bd6089b5 | ||
|
410fe15507 | ||
|
f1bf64a8ff | ||
|
16b268f0ca | ||
|
f135e18522 | ||
|
3e43b27e83 | ||
|
3799f6c69e | ||
|
e6f4df3442 | ||
|
af96a957cd | ||
|
02cde27a12 | ||
|
c206e60ad4 | ||
|
c363b45e0d | ||
|
f1dfa63764 | ||
|
e296938dd4 | ||
|
db93456027 | ||
|
7980a9e932 | ||
|
af661716a0 | ||
|
f52493f270 | ||
|
81a9fbb9bd | ||
|
13214843d8 | ||
|
3791635143 | ||
|
c5c8724a04 | ||
|
b171de3375 | ||
|
0fcef20bb3 | ||
|
2fb162e391 | ||
|
6e264724f8 | ||
|
a730259d97 | ||
|
d5652ade63 | ||
|
5d6be39a0c | ||
|
0006d838f5 | ||
|
1f8ea30735 | ||
|
9e3936b151 | ||
|
56e7b05d99 | ||
|
186b82d71d | ||
|
e4fa1aa418 | ||
|
258476e14f | ||
|
82c64e6e76 | ||
|
73fd2b23a5 | ||
|
80f5856764 | ||
|
92d8203447 | ||
|
fe462398ad | ||
|
b4b7e9a3c7 | ||
|
657c04a041 | ||
|
e3a2c70ccb | ||
|
f632acb6c2 | ||
|
403a4684e5 | ||
|
8f0a31dc1e | ||
|
f3202b0508 | ||
|
d9c11bb853 | ||
|
5a00a2c441 | ||
|
20ab8de06d | ||
|
c8042e92df | ||
|
282e3c2f1f | ||
|
aad4dda353 | ||
|
b8c33571e7 | ||
|
c0723e3d48 | ||
|
c978c8e027 | ||
|
0d188d39d5 | ||
|
dc0d094610 | ||
|
2e472f84a7 | ||
|
f3a160598f | ||
|
eec293191b | ||
|
5cd6d9a0f1 | ||
|
8bf3d6694a | ||
|
1e1d917730 | ||
|
80fe8f837e | ||
|
e5bf1b976a | ||
|
d45cd93278 | ||
|
df85a9a63a | ||
|
af1e69ea1e | ||
|
b915252e7e | ||
|
a6ea520224 | ||
|
9b9627e4b6 | ||
|
379272efa3 | ||
|
e364d254ed | ||
|
6aadb63b82 | ||
|
f3aa937ce2 | ||
|
9c7577c5c2 | ||
|
0b36d4c9d6 | ||
|
c64d80fef9 | ||
|
40f467fb72 | ||
|
f75b67de2f | ||
|
befb4796f9 | ||
|
db949270f5 | ||
|
118e59ac5c | ||
|
7a2e1e0511 | ||
|
764a701610 | ||
|
9cd6c025d5 | ||
|
ddfdf02b34 | ||
|
0e054cd4a0 | ||
|
3c51af78a2 | ||
|
0732c6158a | ||
|
cfc07d7b0d | ||
|
4c95605711 | ||
|
4917380716 | ||
|
4fa82f4c73 | ||
|
1794d58a5b | ||
|
354e3adc04 | ||
|
c426b27287 | ||
|
3980de94a4 | ||
|
cbb6b7819a | ||
|
3e465cb761 | ||
|
d97b8f8faa | ||
|
822b4429f3 | ||
|
0d97118cfb | ||
|
3d1ab8c5b9 | ||
|
15cec1ac10 | ||
|
3da2a3ef3d | ||
|
d74ca3ecf5 | ||
|
0f8786f8b1 | ||
|
bccf95a088 | ||
|
0b84cf401d | ||
|
179ccbc08c | ||
|
8df84ed217 | ||
|
0b227b50b8 | ||
|
65b79b5ea0 | ||
|
23fcb4f87f | ||
|
69830b9c03 | ||
|
700cedd69b | ||
|
92aabbdcec | ||
|
a6c1b2eaf3 | ||
|
ed184ab520 | ||
|
5a40fdd7e1 | ||
|
c9bcc45d7c | ||
|
15446f35a5 | ||
|
7cc37ff2cb | ||
|
e57424ec35 | ||
|
6c0a2eaefc | ||
|
fdb14f23f2 | ||
|
52c6f93c9a | ||
|
76aec2d575 | ||
|
064b70f4c0 | ||
|
bf28afb651 | ||
|
b9f5a4f745 | ||
|
ac187f1e9c | ||
|
6309d4c43d | ||
|
1eaab5e410 | ||
|
c6a9e7aa4c | ||
|
bb252e326f | ||
|
3080250888 | ||
|
8c8067c624 | ||
|
ee25c69cd7 | ||
|
d2b1eaaaa9 | ||
|
d42b31bee6 | ||
|
11593bb887 | ||
|
cd79d26ed5 | ||
|
860dbacf1b | ||
|
aad362fee3 | ||
|
e8df01fab6 | ||
|
3dc467e208 | ||
|
3801382ffe | ||
|
6e6903e073 | ||
|
3698ab5aaa | ||
|
04161a0a5f | ||
|
f3106097af | ||
|
8345ada757 | ||
|
dc382b5288 | ||
|
c47323e358 | ||
|
34e6d29d1f | ||
|
0de00003c6 | ||
|
581f4c6194 | ||
|
1a391fc9c3 | ||
|
47946b1cb7 | ||
|
3eab8eb3dd | ||
|
f9b7b6a413 | ||
|
39088ab003 | ||
|
c1dde29ef6 | ||
|
d38edfc6ca | ||
|
0e59dba914 | ||
|
d4697a17a3 | ||
|
5caa3b13e6 | ||
|
abe6bf7947 | ||
|
90a76ec60b | ||
|
8fe3383976 | ||
|
1762d1e72d | ||
|
c90b485089 | ||
|
bcf784254f | ||
|
c2f65af8bf | ||
|
0ce0aa4d2c | ||
|
9306a56da0 | ||
|
bc53c9b208 | ||
|
6de75e4b9b | ||
|
ab1e0638fb | ||
|
bf8df261ad | ||
|
d4afcc0b7e | ||
|
6ead2d1738 | ||
|
abc456e587 | ||
|
5d6be2aeb4 | ||
|
c335754dec | ||
|
33b5ba35d4 | ||
|
0b20a9c923 | ||
|
c6cef6bbce | ||
|
d4873dbc6b | ||
|
b0a5494a8f | ||
|
6f91b16403 | ||
|
c9588fcbb0 | ||
|
8643231019 | ||
|
105c737609 | ||
|
f817308080 | ||
|
a0e2c82c62 | ||
|
5b4faf811f | ||
|
b88fd9168f | ||
|
39448160f1 | ||
|
615f96012f | ||
|
0213001acb | ||
|
e3cf6b9c54 | ||
|
8c89c37775 | ||
|
d4c90d41a0 | ||
|
ef0fe65c07 | ||
|
ace375aacb | ||
|
16d3c36391 | ||
|
6fc6fa0f41 | ||
|
71e47ce976 | ||
|
5de04f965a | ||
|
cb7534c823 | ||
|
bf3004e4bf | ||
|
e7eaa8d8a9 | ||
|
7b241cebeb | ||
|
9fbdbcb054 | ||
|
1a68fed349 | ||
|
148c9cdfe6 | ||
|
ea35ec4d6e | ||
|
9d09b10537 | ||
|
2f811f99de | ||
|
7ebb57c82b | ||
|
510f4e02c8 | ||
|
dbf42db0fc | ||
|
0804413c41 | ||
|
5c3aba176d | ||
|
da9f9d8964 | ||
|
61e0a2a0f4 | ||
|
b40db06ef3 | ||
|
6c43cac067 | ||
|
48154a090a | ||
|
f55ed01fb5 | ||
|
d9af357663 | ||
|
29cb0211db | ||
|
2df76617c1 | ||
|
c339dc1a07 | ||
|
96af0e6ebb | ||
|
f65a838594 | ||
|
4a8533aa11 | ||
|
9bcb470caa | ||
|
d0ccd5d263 | ||
|
a5d4475f45 | ||
|
b845524134 | ||
|
27ba28237a | ||
|
61a975bf36 | ||
|
9b9432090b | ||
|
53f046a74d | ||
|
e93ff4243f | ||
|
7107acb15c | ||
|
2a7f7af02c | ||
|
92ae748498 | ||
|
5315ec0c10 | ||
|
f1af52baa1 | ||
|
2ef943394d | ||
|
f1dba9f89e | ||
|
2f3ef5359f | ||
|
7f643aadd8 | ||
|
870b3b9a1c | ||
|
f40fb6b099 | ||
|
27fa4c0cdf | ||
|
0869140756 | ||
|
08a50efb08 | ||
|
633c692083 | ||
|
04fb9dd9e0 | ||
|
768d7961a6 | ||
|
e899127137 | ||
|
57c96b89a1 | ||
|
c762c62029 | ||
|
320fe18654 | ||
|
316fac0161 | ||
|
37ffeb8121 | ||
|
610267a3ea | ||
|
744bf9f971 | ||
|
275b383be7 | ||
|
ae8450f4fb | ||
|
f53292cb11 | ||
|
4d146c93d4 | ||
|
a7210f76d1 | ||
|
101f0e8181 | ||
|
ef9c2cb223 | ||
|
f6afc5a2bb | ||
|
e090fd4495 | ||
|
8e76d13a96 | ||
|
c2eae676bf | ||
|
c4f15706ee | ||
|
127e522ed8 | ||
|
b9dde78466 | ||
|
77c9f54f5c | ||
|
be8fe24b6e | ||
|
f1e93be694 | ||
|
22ce079222 | ||
|
560bf345da | ||
|
2238ea8d52 | ||
|
c726675189 | ||
|
b7a0c53b0b | ||
|
5fe9d53cfa | ||
|
40fbb02149 | ||
|
6d77eb9b10 | ||
|
eb0c38f90f | ||
|
c79f0c83a7 | ||
|
7b952e3c94 | ||
|
8f43ab9573 | ||
|
c58cd835d2 | ||
|
07c4e606e1 | ||
|
c2e940c4f9 | ||
|
fff8cf1c34 | ||
|
7a7a74d93e | ||
|
9bcd00bfa8 | ||
|
8d1971e0b2 | ||
|
503e33a683 | ||
|
1c63cc7ee9 | ||
|
c2dbd40027 | ||
|
e177ad55c1 | ||
|
4a61867f79 | ||
|
28b26c892b | ||
|
4198236f6a | ||
|
8215b5de83 | ||
|
0d2419e402 | ||
|
efa912c373 | ||
|
9cdc1dde0e | ||
|
1f9e1285af | ||
|
96332720e5 | ||
|
320103af77 | ||
|
bc5d3b6c3a | ||
|
2b5882855b | ||
|
f2ce5647f2 | ||
|
3e5872d0b1 | ||
|
3d2524532f | ||
|
64e66acb01 | ||
|
b2ea4dbab7 | ||
|
092958441b | ||
|
ad549cc5d6 | ||
|
0ff7a1c72b | ||
|
7cead7b168 | ||
|
999d5d58ec | ||
|
d540ec7f8d | ||
|
e3aa9b8121 | ||
|
c0d4cb918a | ||
|
d2dce46184 | ||
|
0ece5a530c | ||
|
ee9f6d73d6 | ||
|
ec2fefee30 | ||
|
8b47378720 | ||
|
acf98cc6d4 | ||
|
eebc2d9a79 | ||
|
a5649bdaeb | ||
|
22ce71e792 | ||
|
b0ec3ad0c9 | ||
|
afa2969b39 | ||
|
515ae7693b | ||
|
3f39b6366f | ||
|
f484dc8bd8 | ||
|
3309bc818a | ||
|
0fd84f5864 | ||
|
84d7188f0c | ||
|
1bfcd0ac6e | ||
|
8fef32b954 | ||
|
318c57df12 | ||
|
6e44d6c7e4 | ||
|
24ce6180c4 | ||
|
bb0900093d | ||
|
dde8291597 | ||
|
4d0a695588 | ||
|
fa315cf44a | ||
|
182732b112 | ||
|
7cb962de82 | ||
|
126ec1977b | ||
|
5af1dce914 | ||
|
84f4c8d3fa | ||
|
f0824903b9 | ||
|
02662ecd11 | ||
|
83a3bc44af | ||
|
5d5d1ca7b2 | ||
|
030905fafa | ||
|
82d987cb1d | ||
|
1fab37f74e | ||
|
e3067095f4 | ||
|
04e92766fc | ||
|
867eba7381 | ||
|
caec1ed576 | ||
|
3ae9ae8728 | ||
|
e0a249f9a4 | ||
|
31deac5117 | ||
|
8edca631e6 | ||
|
c5d7f26a8c | ||
|
bb9e09ef51 | ||
|
2d1142743e | ||
|
0300447298 | ||
|
9d25db0e86 | ||
|
962a76759f | ||
|
5518672677 | ||
|
e685ff8837 | ||
|
2623ff5484 | ||
|
adee070ee6 | ||
|
2ed1b969fb | ||
|
bb911296a6 | ||
|
51b24cbac9 | ||
|
06f0c6c32c | ||
|
cdf3361f2a | ||
|
3c2db734d6 | ||
|
5ca887d839 | ||
|
619cb730ef | ||
|
40927178f4 | ||
|
894cd5814f | ||
|
17ff47f6d5 | ||
|
082ed8745b | ||
|
a09e182238 | ||
|
11540a8bff | ||
|
aba54ebbbe | ||
|
bcbdcbd1ff | ||
|
f3703f433e | ||
|
81d28bbb4c | ||
|
502d0d1b53 | ||
|
cb5a1daa40 | ||
|
eb0e1c393f | ||
|
68e729e192 | ||
|
dc65958c17 | ||
|
8ed5dd3a30 | ||
|
a2c4585914 | ||
|
bac5f00190 | ||
|
d8509b426d | ||
|
4348b0b873 | ||
|
287e50f81a | ||
|
341f5b46f6 | ||
|
0cd2b8e2c0 | ||
|
38ad97f24f | ||
|
ba6bde9b09 | ||
|
a6385bed71 | ||
|
e9b92aea7b | ||
|
ffbc7d0ea1 | ||
|
0afa5aba63 | ||
|
cf8ce380b7 | ||
|
f40b428ac2 | ||
|
907e07a4c4 | ||
|
486a6ba8c6 | ||
|
c99958c327 | ||
|
ed06480e75 | ||
|
e59dd9d9d4 | ||
|
a8963c3ba2 | ||
|
9921abc8bd | ||
|
90181759cd | ||
|
26f1c5f1dc | ||
|
ce7fd1b0e2 | ||
|
d2f2d1d0b9 | ||
|
f7c661b5e9 | ||
|
34b2419427 | ||
|
e0dadea0ff | ||
|
b94697678e | ||
|
530a93794f | ||
|
d55830902b | ||
|
6684f0d5c7 | ||
|
c83099c8d0 | ||
|
19659296eb | ||
|
9ed137a119 | ||
|
36dbae7642 | ||
|
5fe7af6489 | ||
|
f775d6e049 | ||
|
7d10d04768 | ||
|
3c4da64348 | ||
|
66822c6a81 | ||
|
856f8fb908 | ||
|
ae0cab36dc | ||
|
0bd8118673 | ||
|
dd4fbc0194 | ||
|
899ac663fc | ||
|
011c098c63 | ||
|
c33223a0eb | ||
|
ce5789690d | ||
|
5edc36d6fc | ||
|
31a731deb7 | ||
|
48bd6b2f81 | ||
|
b4762238ed | ||
|
7587517499 | ||
|
c53a75bc38 | ||
|
5803c1e760 | ||
|
f1405cdb6c | ||
|
4a766b9750 | ||
|
b9b44931ac | ||
|
4deb28f24e | ||
|
3a491b879c | ||
|
a0e77032cf | ||
|
73fb1f1549 | ||
|
22b1f871a8 | ||
|
b1d78e34db | ||
|
ae2b6e3bb7 | ||
|
1b4d0d0bb0 | ||
|
19cd11cc8e | ||
|
6f570a08e5 | ||
|
75772d874f | ||
|
704ddc2089 | ||
|
9987c90faf | ||
|
b801e176aa | ||
|
432f28ecd1 | ||
|
af4cac91b1 | ||
|
f8b96c562a | ||
|
af655ff392 | ||
|
9803bd731c | ||
|
3b8aac4c55 | ||
|
1b4ace329e | ||
|
dd4467043a | ||
|
57da3416c5 | ||
|
ab22464d55 | ||
|
e7e0ae3784 | ||
|
c949032fc7 | ||
|
722164711c | ||
|
2fba79929d | ||
|
81b87e9ca4 | ||
|
d9841eeea3 | ||
|
0bdc1d9f57 | ||
|
2f9f873f4b | ||
|
7a4542cd50 | ||
|
ea07b83fd0 | ||
|
0ab9c23bb9 | ||
|
9e4f39b4fb | ||
|
ee5b210682 | ||
|
7a7b8d3e27 | ||
|
40fa8559e5 | ||
|
3e3fe92567 | ||
|
9ef3fdc857 | ||
|
23e3af4a09 | ||
|
af51441d88 | ||
|
241031f1fa | ||
|
16bdd76be1 | ||
|
d6ec1d7d6b | ||
|
d05b2dd8c2 | ||
|
1c4d021b67 | ||
|
d0d9712ac3 | ||
|
ce6ae1d98c | ||
|
1c7446bf9a | ||
|
23b19b76b5 | ||
|
6b948c82d7 | ||
|
a583cc9b0e | ||
|
ba65cad1cd | ||
|
b2a383a9cb | ||
|
1d441ab657 | ||
|
e16d9ace34 | ||
|
2ebac8207f | ||
|
99d6599747 | ||
|
228ca0bfac | ||
|
cc9ff34e45 | ||
|
c70da6641f | ||
|
657ccaf226 | ||
|
65ca688da6 | ||
|
012cce1ac7 | ||
|
c6c29b29b1 | ||
|
4f1b917e42 | ||
|
c24d36c02e | ||
|
f7d8240d2c | ||
|
b60f9863c6 | ||
|
f8bb565fa5 | ||
|
8401b5b0ee | ||
|
b09fb1047f | ||
|
75632a1490 | ||
|
a676e738e0 | ||
|
0826cb50bd | ||
|
75fee6784e | ||
|
78f7285e00 | ||
|
8210f5c7e5 | ||
|
f3f52efe18 | ||
|
7e05416da6 | ||
|
76e5495e15 | ||
|
59404752f9 | ||
|
6a2e8739d1 | ||
|
8178f87e61 | ||
|
18d847275a | ||
|
54ee36a6aa | ||
|
9f8023b91f | ||
|
cb6269eddb | ||
|
346b42fba5 | ||
|
5430d65799 | ||
|
42b543cd24 | ||
|
ee579280c7 | ||
|
9a28eee477 | ||
|
e8c1f4ec2b | ||
|
b3cf518628 | ||
|
06667fc37c | ||
|
4f02c9ca88 | ||
|
c00a7c571a | ||
|
90f148afaf | ||
|
3b694741cc | ||
|
955c8a18f0 | ||
|
1d177ed907 | ||
|
b378f5b0a7 | ||
|
3406dbb29c | ||
|
4c80eb98e5 | ||
|
3589dca717 | ||
|
535baaebcf | ||
|
9867bdfcff | ||
|
97605498a6 | ||
|
65c6cb05ee | ||
|
3cd098bfc7 | ||
|
020d1f6e30 | ||
|
cf6d7fbb76 | ||
|
5422ba42b6 | ||
|
98229a5ace | ||
|
1c43d57233 | ||
|
e976126f2e | ||
|
c3586cb51a | ||
|
7abdc17711 | ||
|
780bfe0cbe | ||
|
d4e4c1505b | ||
|
47c2715568 | ||
|
8aa54fe9fd | ||
|
053dc2bea5 | ||
|
68ce03797a | ||
|
f36e118609 | ||
|
b55dc0ac48 | ||
|
2838e3319b | ||
|
99603d3d90 | ||
|
d9ab7efcd6 | ||
|
8b15bb9e66 | ||
|
b35c45bf5a | ||
|
650e65d4b4 | ||
|
7b892fac9c | ||
|
07e9f0f54a | ||
|
2c801abb06 | ||
|
06e3051ad1 | ||
|
1fe730f514 | ||
|
496f0755b1 | ||
|
6ad1dd72d6 | ||
|
867253436d | ||
|
fb4ddb7d8d | ||
|
7a8be0e87e | ||
|
fb3a3ea7e6 | ||
|
f628c540a4 | ||
|
88f693bb71 | ||
|
fef844cc68 | ||
|
139ddbd1de | ||
|
685e058fe6 | ||
|
7c499c2212 | ||
|
3ec5119933 | ||
|
6ee0890c5e | ||
|
e34d38182c | ||
|
796db5dfae | ||
|
56b8b6cd03 | ||
|
b9e9af0361 | ||
|
e17012801f | ||
|
f44b261cd7 | ||
|
cbcb4374fc | ||
|
bdae3c56c0 | ||
|
a06e18a4bd | ||
|
b2eee3ffd3 | ||
|
e797db8d48 | ||
|
69f30a2631 | ||
|
c133884ce4 | ||
|
66d7ec5734 | ||
|
86721490e1 | ||
|
937739cb0d | ||
|
d3be886dac | ||
|
07f7632d64 | ||
|
6fed376c50 | ||
|
8f66cbee91 | ||
|
a0da648214 | ||
|
9c7066ae35 | ||
|
ec5d3e55c7 | ||
|
0b58562a4e | ||
|
763d66f367 | ||
|
9d4dc61807 | ||
|
5b281d22ed | ||
|
3819ec9dd1 | ||
|
f93915075e | ||
|
5f829ac1cd | ||
|
76d25a27b4 | ||
|
7dbf1bb8bb | ||
|
d7c25ce0b5 | ||
|
c5ca4df389 | ||
|
bc76f2af67 | ||
|
4e9d129dd3 | ||
|
d4504c39c6 | ||
|
84f9c0ef1f | ||
|
702abb2830 | ||
|
4f1a4c4c8a | ||
|
c30327c043 | ||
|
b8d2a352ae | ||
|
11dba90440 | ||
|
ca956408f6 | ||
|
9e2b192054 | ||
|
0e5b79f1dd | ||
|
81be4c238c | ||
|
c311a65073 | ||
|
2ff280d34c | ||
|
caa826ca06 | ||
|
3c84c21318 | ||
|
b8e15b42fa | ||
|
0f785e8bd0 | ||
|
58e447f7bb | ||
|
cde93c68dc | ||
|
c1c158ccda | ||
|
2b81529844 | ||
|
a5f623a86a | ||
|
17e5ba715e | ||
|
92666e4444 | ||
|
92eff402af | ||
|
c61ae5da42 | ||
|
65a3bff645 | ||
|
3c1599323b | ||
|
f254283dc6 | ||
|
6cb9676250 | ||
|
ec0c3bf96e | ||
|
c79f3cde22 | ||
|
5ab976dd51 | ||
|
4faad61a7c | ||
|
17dba36e77 | ||
|
b612180c22 | ||
|
ae52648950 | ||
|
817eeb9734 | ||
|
46f6a041a0 | ||
|
74802edd44 | ||
|
55709169eb | ||
|
e4ec14767f | ||
|
9422b016d7 | ||
|
78444ff25c | ||
|
3d97280f52 | ||
|
5772c70216 | ||
|
2b40e49e6e | ||
|
219b258a54 | ||
|
e26f435c2e | ||
|
24f75cd618 | ||
|
12ed714a9e | ||
|
08ecf2c9a4 | ||
|
36484309d1 | ||
|
f7b4f57028 | ||
|
ab2f7d8845 | ||
|
6dc193500d | ||
|
0e23f35438 | ||
|
34845910ec | ||
|
603af2fb19 | ||
|
e320b010c7 | ||
|
9ebdd9f95c | ||
|
d09e19ce1d | ||
|
9638113244 | ||
|
5469637f2b | ||
|
5696a5249f | ||
|
1f99e2924d | ||
|
8bbf9d25b6 | ||
|
ceb4747eea | ||
|
a24a65de2f | ||
|
6e17b3b76e | ||
|
f75fc9a2fb | ||
|
112df46200 | ||
|
e97231683a | ||
|
c74ed3d2b9 | ||
|
bb37e87b6e | ||
|
d2ea53deb1 | ||
|
6909f5cba6 | ||
|
84048617c9 | ||
|
fca8de40a1 | ||
|
551cb5f50f | ||
|
1f2c97f76f | ||
|
2b6cc5378f | ||
|
c1b48be75c | ||
|
d3df0ff1d3 | ||
|
e5b837f183 | ||
|
eb04f3b079 | ||
|
b8aa6f15c9 | ||
|
5595bfc0d8 | ||
|
2ef9982f63 | ||
|
ee2cdc7763 | ||
|
3e523ddd09 | ||
|
ca51b45f04 | ||
|
9a04f90bbd | ||
|
12d5e4da44 | ||
|
20f5a96fe0 | ||
|
629c4af3c8 | ||
|
5baa54e81c | ||
|
2a132718d0 | ||
|
14ec1950b9 | ||
|
c6754fe838 | ||
|
712b9e9610 | ||
|
68fb214f85 | ||
|
59292571e0 | ||
|
31665e795c | ||
|
a7bc4010b9 | ||
|
d87f24f17a | ||
|
2c0db2f043 | ||
|
c495461ffb | ||
|
782271aa3c | ||
|
4abfc3907b | ||
|
e6b39e5f1c | ||
|
ae75ffc31a | ||
|
79f9e78daf | ||
|
81c0c56e5a | ||
|
d9d1e9e0e0 | ||
|
9c7a0f7e58 | ||
|
89801f043f | ||
|
d2151f9cd0 | ||
|
82a95367ae | ||
|
221dad7663 | ||
|
5305286312 | ||
|
bbf7e4a936 | ||
|
8b500926ee | ||
|
940884e4bd | ||
|
29c0473b64 | ||
|
e1efa09260 | ||
|
35c01b9685 | ||
|
dcc8cca6cd | ||
|
37b2c3faab | ||
|
64751b7b5a | ||
|
1946d4f470 | ||
|
9623645cfa | ||
|
5a10bd3d4b | ||
|
d4f6b3bbef | ||
|
c2be44a848 | ||
|
7de79fc753 | ||
|
536234a9c6 | ||
|
2ac926dfb2 | ||
|
be193a236e | ||
|
d9087b4f7c | ||
|
cad3311afb | ||
|
6f14645a5f | ||
|
6a6a5af3b2 | ||
|
9477e1b55f | ||
|
85f74c80e8 | ||
|
470c47f45c | ||
|
0fc9f7f0b4 | ||
|
6fd74bccb0 | ||
|
48b2cff53d | ||
|
bbf7d50295 | ||
|
256ed12b51 | ||
|
dc80d35088 | ||
|
4203ce5d51 | ||
|
1c3a33ab49 | ||
|
60a9833130 | ||
|
1d5fc6a4bf | ||
|
aa6ddb73fe | ||
|
10497e9231 | ||
|
5601c8b6a1 | ||
|
5066e4b6e0 | ||
|
7176ba5a0a | ||
|
6985808624 | ||
|
3ac97e44ab | ||
|
6477179231 | ||
|
2662fce74d | ||
|
f48311051e | ||
|
b6a972c5fe | ||
|
d959c07e25 | ||
|
50cf3bf4f7 | ||
|
f0ce7ea61e | ||
|
b5317f8e46 | ||
|
00d2e24dd2 | ||
|
c0bd3b5ff0 | ||
|
94b4009397 | ||
|
ae36d66ddc | ||
|
7c6505cc55 | ||
|
9074258b78 | ||
|
4f16bbe5f5 | ||
|
81b0bab084 | ||
|
d29a18e56f | ||
|
dfb821d3b5 | ||
|
a28a207774 | ||
|
eff96cc140 | ||
|
4b971f84fd | ||
|
01ba276455 | ||
|
bf04b3e57d | ||
|
f024de4350 | ||
|
3c229443e8 | ||
|
4e49c45021 | ||
|
8448d719e7 | ||
|
ad6be21b56 | ||
|
28f2b7fc81 | ||
|
3535c7c4cd | ||
|
71add60f59 | ||
|
57c188d01d | ||
|
4a9c7d2f30 | ||
|
b5c2cbc597 | ||
|
979468e7fb | ||
|
0bb8e3af80 | ||
|
9ae7b9cf01 | ||
|
3a8058ec09 | ||
|
e984057ceb | ||
|
c5dac44c8f | ||
|
adb1bd2ad0 | ||
|
0965a84929 | ||
|
cf92446cf3 | ||
|
04d4c6d8f0 | ||
|
5ecee2b9f7 | ||
|
7de3b16dc3 | ||
|
f575f6c94c | ||
|
2d248ec8ca | ||
|
87491dc3b5 | ||
|
0126aa5018 | ||
|
c15671fa78 | ||
|
5a201819ac | ||
|
f799ab563c | ||
|
b7e007c37b | ||
|
fa22e11c5f | ||
|
4c02205454 | ||
|
d62eee3379 | ||
|
2c325eb124 |
870 changed files with 48629 additions and 38125 deletions
|
@ -19,7 +19,7 @@ cd $DocumentRoot
|
|||
# copy the .htaccess-dist file to .htaccess so that rewrite rules work
|
||||
cp $DocumentRoot/.htaccess-dist $DocumentRoot/.htaccess
|
||||
|
||||
bin/composer.phar --no-dev install
|
||||
bin/composer.phar install
|
||||
|
||||
# install friendica
|
||||
bin/console autoinstall -f /tmp/autoinstall.config.php
|
||||
|
|
141
.github/workflows/code-quality.yml
vendored
Normal file
141
.github/workflows/code-quality.yml
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
name: Code Quality
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
code-style:
|
||||
name: PHP-CS-Fixer (PHP ${{ matrix.php }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: ['ubuntu-latest']
|
||||
php: ['8.3']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Setup PHP with composer and extensions
|
||||
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: xdebug
|
||||
tools: none
|
||||
|
||||
- name: Clone addon repository
|
||||
run: git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon
|
||||
|
||||
- name: Install PHP-CS-Fixer
|
||||
run: composer install --working-dir=bin/dev/php-cs-fixer
|
||||
|
||||
- name: Run PHP-CS-Fixer
|
||||
continue-on-error: true
|
||||
run: bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix --diff --dry-run
|
||||
|
||||
phpstan:
|
||||
name: PHPStan (PHP ${{ matrix.php }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: ['ubuntu-latest']
|
||||
php: ['8.4']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Setup PHP with composer and extensions
|
||||
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: xdebug
|
||||
tools: none
|
||||
|
||||
- name: Clone addon repository
|
||||
run: git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon
|
||||
|
||||
- name: Install Composer dependencies
|
||||
uses: "ramsey/composer-install@v2"
|
||||
|
||||
- name: Run PHPStan
|
||||
run: composer run phpstan
|
||||
|
||||
phpstan-addons:
|
||||
name: PHPStan in addons (PHP ${{ matrix.php }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: ['ubuntu-latest']
|
||||
php: ['8.4']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Setup PHP with composer and extensions
|
||||
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: xdebug
|
||||
tools: none
|
||||
|
||||
- name: Clone addon repository
|
||||
run: git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon
|
||||
|
||||
- name: Install Composer dependencies
|
||||
uses: "ramsey/composer-install@v2"
|
||||
|
||||
- name: Run PHPStan in addons
|
||||
run: composer run phpstan-addons
|
||||
|
||||
phpmd:
|
||||
name: PHPMD (PHP ${{ matrix.php }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: ['ubuntu-latest']
|
||||
php: ['8.4']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Setup PHP with composer and extensions
|
||||
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: none
|
||||
tools: none
|
||||
|
||||
- name: Clone addon repository
|
||||
run: git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon
|
||||
|
||||
- name: Install Composer dependencies
|
||||
uses: "ramsey/composer-install@v2"
|
||||
|
||||
- name: Run PHPMD
|
||||
run: vendor/bin/phpmd src/ text .phpmd-ruleset.xml --color
|
129
.github/workflows/tests.yml
vendored
Normal file
129
.github/workflows/tests.yml
vendored
Normal file
|
@ -0,0 +1,129 @@
|
|||
# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
name: CI tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
name: Unit-Tests (PHP ${{ matrix.php }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: ['ubuntu-latest']
|
||||
php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Setup PHP with composer and extensions
|
||||
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: xdebug
|
||||
tools: none
|
||||
|
||||
- name: Clone addon repository
|
||||
run: git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon
|
||||
|
||||
- name: Install Composer dependencies
|
||||
uses: "ramsey/composer-install@v2"
|
||||
|
||||
- name: Run Unit tests
|
||||
run: composer run test:unit
|
||||
|
||||
database-tests:
|
||||
name: Database-Tests (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
mariadb:
|
||||
image: mariadb:latest
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: true
|
||||
MYSQL_DATABASE: test
|
||||
MYSQL_PASSWORD: test
|
||||
MYSQL_USER: test
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379/tcp
|
||||
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
memcached:
|
||||
image: memcached
|
||||
ports:
|
||||
- 11211/tcp
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: pecl, composer
|
||||
extensions: pdo_mysql, gd, zip, opcache, ctype, pcntl, ldap, apcu, memcached, redis, imagick, memcache
|
||||
coverage: xdebug
|
||||
ini-values: apc.enabled=1, apc.enable_cli=1
|
||||
|
||||
- name: Clone addon repository
|
||||
run: git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon
|
||||
|
||||
# Install composer dependencies and handle caching in one go.
|
||||
# @link https://github.com/marketplace/actions/install-php-dependencies-with-composer
|
||||
- name: "Install Composer dependencies"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
|
||||
- name: Start mysql service
|
||||
run: sudo /etc/init.d/mysql start
|
||||
|
||||
- name: Copy default Friendica config
|
||||
run: cp config/local-sample.config.php config/local.config.php
|
||||
|
||||
- name: Verify MariaDB connection
|
||||
env:
|
||||
PORT: ${{ job.services.mariadb.ports[3306] }}
|
||||
run: |
|
||||
while ! mysqladmin ping -h"127.0.0.1" -P"$PORT" --silent; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
- name: Setup MYSQL database
|
||||
env:
|
||||
PORT: ${{ job.services.mariadb.ports[3306] }}
|
||||
run: |
|
||||
mysql -h"127.0.0.1" -P"$PORT" -utest -ptest test < database.sql
|
||||
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover clover.xml
|
||||
env:
|
||||
MYSQL_HOST: 127.0.0.1
|
||||
MYSQL_PORT: ${{ job.services.mariadb.ports[3306] }}
|
||||
MYSQL_DATABASE: test
|
||||
MYSQL_PASSWORD: test
|
||||
MYSQL_USER: test
|
||||
REDIS_PORT: ${{ job.services.redis.ports[6379] }}
|
||||
REDIS_HOST: 127.0.0.1
|
||||
MEMCACHED_PORT: ${{ job.services.memcached.ports[11211] }}
|
||||
MEMCACHE_PORT: ${{ job.services.memcached.ports[11211] }}
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -72,7 +72,6 @@ venv/
|
|||
/.idea
|
||||
|
||||
#ignore addons directory
|
||||
/addons
|
||||
/addon
|
||||
|
||||
#ignore base .htaccess
|
||||
|
@ -90,6 +89,7 @@ venv/
|
|||
#Ignore cache files
|
||||
.php_cs.cache
|
||||
.php-cs-fixer.cache
|
||||
.phpmd.result-cache.php
|
||||
|
||||
#ignore avatar picture cache path
|
||||
/avatar
|
||||
|
|
26
.phpmd-ruleset.xml
Normal file
26
.phpmd-ruleset.xml
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0"?>
|
||||
<ruleset name="Friendica Ruleset"
|
||||
xmlns="http://pmd.sf.net/ruleset/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
|
||||
http://pmd.sf.net/ruleset_xml_schema.xsd"
|
||||
xsi:noNamespaceSchemaLocation="
|
||||
http://pmd.sf.net/ruleset_xml_schema.xsd">
|
||||
<description>
|
||||
PHPMD ruleset for friendica code.
|
||||
</description>
|
||||
|
||||
<rule ref="rulesets/codesize.xml/ExcessiveClassComplexity">
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
<property name="maximum" value="800" />
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="rulesets/codesize.xml/CyclomaticComplexity">
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
<property name="reportLevel" value="100" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
3
.phpmd-ruleset.xml.license
Normal file
3
.phpmd-ruleset.xml.license
Normal file
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
52
.phpstan-addons.neon
Normal file
52
.phpstan-addons.neon
Normal file
|
@ -0,0 +1,52 @@
|
|||
# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
parameters:
|
||||
level: 3
|
||||
|
||||
paths:
|
||||
- addon/
|
||||
|
||||
excludePaths:
|
||||
analyse:
|
||||
- addon/*/lang/*
|
||||
- addon/*/vendor/*
|
||||
- addon/convert/UnitConvertor.php
|
||||
- addon/pumpio/oauth/*
|
||||
|
||||
scanDirectories:
|
||||
- mod
|
||||
- src
|
||||
- static
|
||||
- vendor
|
||||
- view
|
||||
|
||||
dynamicConstantNames:
|
||||
- DB_UPDATE_VERSION
|
||||
|
||||
ignoreErrors:
|
||||
|
||||
-
|
||||
# Ignore missing SMTP class in PHPMailer 5.2.21
|
||||
# see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php
|
||||
message: '(^.+ an unknown class SMTP\.$)'
|
||||
path: addon/mailstream/phpmailer
|
||||
|
||||
-
|
||||
# Ignore missing SMTP class in PHPMailer 5.2.21
|
||||
# see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php
|
||||
message: '(^Property .+ has unknown class SMTP as its type\.$)'
|
||||
path: addon/mailstream/phpmailer
|
||||
|
||||
-
|
||||
# Ignore missing SMTP class in PHPMailer 5.2.21
|
||||
# see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php
|
||||
message: '(^Method .+ has invalid return type SMTP\.$)'
|
||||
path: addon/mailstream/phpmailer
|
||||
|
||||
-
|
||||
# Ignore missing SMTP class in PHPMailer 5.2.21
|
||||
# see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php
|
||||
message: '(^Instantiated class SMTP not found\.$)'
|
||||
path: addon/mailstream/phpmailer
|
40
.phpstan.neon
Normal file
40
.phpstan.neon
Normal file
|
@ -0,0 +1,40 @@
|
|||
# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
parameters:
|
||||
level: 3
|
||||
|
||||
paths:
|
||||
- bin/auth_ejabberd.php
|
||||
- bin/console.php
|
||||
- bin/daemon.php
|
||||
- bin/jetstream.php
|
||||
- bin/worker.php
|
||||
- index.php
|
||||
- src/
|
||||
|
||||
scanDirectories:
|
||||
- mod
|
||||
- static
|
||||
- vendor
|
||||
- view
|
||||
|
||||
dynamicConstantNames:
|
||||
- DB_UPDATE_VERSION
|
||||
|
||||
ignoreErrors:
|
||||
-
|
||||
# Ignore missing GdImage class in PHP <= 7.4
|
||||
message: '(^Property .+ has unknown class GdImage as its type\.$)'
|
||||
path: src
|
||||
|
||||
-
|
||||
# Ignore missing IMAP\Connection class in PHP <= 8.0
|
||||
message: '(^Method .+ has invalid return type IMAP\\Connection\.$)'
|
||||
path: src
|
||||
|
||||
-
|
||||
# Ignore missing IMAP\Connection class in PHP <= 8.0
|
||||
message: '(^Parameter .+ has invalid type IMAP\\Connection\.$)'
|
||||
path: src
|
|
@ -39,17 +39,14 @@ steps:
|
|||
check:
|
||||
image: php:8.3
|
||||
commands:
|
||||
- echo "**** Use bin/dev/fix-codestyle.sh in case of errors ****"
|
||||
- apt-get update -q
|
||||
- DEBIAN_FRONTEND=noninteractive apt-get install -q -y git
|
||||
- if [ ! -z "$${CI_COMMIT_PULL_REQUEST}" ]; then
|
||||
git fetch --no-tags origin ${CI_COMMIT_TARGET_BRANCH};
|
||||
CHANGED_FILES="$(git diff --name-only --diff-filter=ACMRTUXB $(git merge-base FETCH_HEAD origin/${CI_COMMIT_TARGET_BRANCH})..${CI_COMMIT_SHA})";
|
||||
git fetch --no-tags --unshallow origin ${CI_COMMIT_TARGET_BRANCH}:refs/remotes/origin/${CI_COMMIT_TARGET_BRANCH};
|
||||
CHANGED_FILES="$(git diff --name-only --diff-filter=ACMRTUXB $(git merge-base ${CI_COMMIT_SHA} origin/${CI_COMMIT_TARGET_BRANCH})..${CI_COMMIT_SHA})";
|
||||
else
|
||||
CHANGED_FILES="$(git diff --name-only --diff-filter=ACMRTUXB ${CI_COMMIT_SHA})";
|
||||
fi
|
||||
- if ! echo "$${CHANGED_FILES}" | grep -qE "^(\\.php-cs-fixer(\\.dist)?\\.php|composer\\.lock)$"; then
|
||||
EXTRA_ARGS=$(printf -- '--path-mode=intersection\n--\n%s' "$${CHANGED_FILES}");
|
||||
else
|
||||
EXTRA_ARGS='';
|
||||
fi
|
||||
- EXTRA_ARGS="--path-mode=intersection -- $${CHANGED_FILES}";
|
||||
- ./bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer check --config=.php-cs-fixer.dist.php -v --diff --using-cache=no $${EXTRA_ARGS}
|
||||
|
|
|
@ -41,8 +41,9 @@ steps:
|
|||
volumes:
|
||||
- /tmp/drone-cache:/tmp/cache
|
||||
composer_install:
|
||||
image: friendicaci/php8.2:php8.2.16
|
||||
image: friendicaci/php8.2:php8.2.28
|
||||
commands:
|
||||
- mkdir addon # create empty addon folder to appease composer
|
||||
- export COMPOSER_HOME=.composer
|
||||
- composer validate
|
||||
- composer install --no-dev --optimize-autoloader
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
matrix:
|
||||
include:
|
||||
- PHP_MAJOR_VERSION: 8.2
|
||||
PHP_VERSION: 8.2.16
|
||||
PHP_VERSION: 8.2.28
|
||||
|
||||
when:
|
||||
branch:
|
||||
|
@ -41,6 +41,7 @@ steps:
|
|||
composer_install:
|
||||
image: friendicaci/php${PHP_MAJOR_VERSION}:php${PHP_VERSION}
|
||||
commands:
|
||||
- mkdir addon # create empty addon folder to appease composer
|
||||
- export COMPOSER_HOME=.composer
|
||||
- ./bin/composer.phar validate
|
||||
- ./bin/composer.phar install --prefer-dist
|
||||
|
|
50
.woodpecker/.phpmd_check.yml
Normal file
50
.woodpecker/.phpmd_check.yml
Normal file
|
@ -0,0 +1,50 @@
|
|||
# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
# The phpmd check is just triggered for PRs and pushes to non-stable branches of Friendica
|
||||
when:
|
||||
branch:
|
||||
exclude: [ stable ]
|
||||
event: [ pull_request, push ]
|
||||
|
||||
# This forces PHP Unit executions at the "opensocial" labeled location (because of access issues with git.friendi.ca)
|
||||
labels:
|
||||
location: opensocial
|
||||
|
||||
steps:
|
||||
restore_cache:
|
||||
image: meltwater/drone-cache:dev
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: "{{ .Repo.Name }}_php${PHP_MAJOR_VERSION}_{{ arch }}_{{ os }}"
|
||||
archive_format: "gzip"
|
||||
mount:
|
||||
- '.composer'
|
||||
volumes:
|
||||
- /tmp/drone-cache:/tmp/cache
|
||||
|
||||
composer_install:
|
||||
image: friendicaci/php8.3:php8.3.17
|
||||
commands:
|
||||
- mkdir addon # create empty addon folder to appease composer
|
||||
- export COMPOSER_HOME=.composer
|
||||
- ./bin/composer.phar install --prefer-dist
|
||||
|
||||
rebuild_cache:
|
||||
image: meltwater/drone-cache:dev
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: "{{ .Repo.Name }}_php${PHP_MAJOR_VERSION}_{{ arch }}_{{ os }}"
|
||||
archive_format: "gzip"
|
||||
mount:
|
||||
- '.composer'
|
||||
volumes:
|
||||
- /tmp/drone-cache:/tmp/cache
|
||||
|
||||
phpmd:
|
||||
image: friendicaci/php8.3:php8.3.17
|
||||
commands:
|
||||
- ./bin/composer.phar run phpmd
|
|
@ -9,11 +9,13 @@ matrix:
|
|||
- PHP_MAJOR_VERSION: 8.0
|
||||
PHP_VERSION: 8.0.30
|
||||
- PHP_MAJOR_VERSION: 8.1
|
||||
PHP_VERSION: 8.1.27
|
||||
PHP_VERSION: 8.1.31
|
||||
- PHP_MAJOR_VERSION: 8.2
|
||||
PHP_VERSION: 8.2.16
|
||||
PHP_VERSION: 8.2.28
|
||||
- PHP_MAJOR_VERSION: 8.3
|
||||
PHP_VERSION: 8.3.3
|
||||
PHP_VERSION: 8.3.17
|
||||
- PHP_MAJOR_VERSION: 8.4
|
||||
PHP_VERSION: 8.4.5
|
||||
|
||||
# This forces PHP Unit executions at the "opensocial" labeled location (because of much more power...)
|
||||
labels:
|
||||
|
@ -24,7 +26,19 @@ when:
|
|||
exclude: [ stable ]
|
||||
event: [ pull_request, push ]
|
||||
|
||||
skip_clone: true
|
||||
|
||||
steps:
|
||||
clone:
|
||||
image: alpine/git
|
||||
commands:
|
||||
- git config --global user.email "no-reply@friendi.ca"
|
||||
- git config --global user.name "Friendica"
|
||||
- git config --global --add safe.directory $CI_WORKSPACE
|
||||
- git clone $CI_REPO_CLONE_URL .
|
||||
- git checkout $CI_COMMIT_BRANCH
|
||||
- git fetch origin $CI_COMMIT_REF
|
||||
- git merge $CI_COMMIT_SHA
|
||||
php-lint:
|
||||
image: php:${PHP_MAJOR_VERSION}
|
||||
commands:
|
||||
|
@ -43,6 +57,7 @@ steps:
|
|||
composer_install:
|
||||
image: friendicaci/php${PHP_MAJOR_VERSION}:php${PHP_VERSION}
|
||||
commands:
|
||||
- git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon
|
||||
- export COMPOSER_HOME=.composer
|
||||
- ./bin/composer.phar validate
|
||||
- ./bin/composer.phar install --prefer-dist
|
||||
|
@ -59,6 +74,20 @@ steps:
|
|||
- '.composer'
|
||||
volumes:
|
||||
- /tmp/drone-cache:/tmp/cache
|
||||
phpstan:
|
||||
image: friendicaci/php${PHP_MAJOR_VERSION}:php${PHP_VERSION}
|
||||
when:
|
||||
matrix:
|
||||
PHP_MAJOR_VERSION: 8.3
|
||||
commands:
|
||||
- bin/composer.phar run phpstan;
|
||||
phpstan-addons:
|
||||
image: friendicaci/php${PHP_MAJOR_VERSION}:php${PHP_VERSION}
|
||||
when:
|
||||
matrix:
|
||||
PHP_MAJOR_VERSION: 8.3
|
||||
commands:
|
||||
- bin/composer.phar run phpstan-addons;
|
||||
test:
|
||||
image: friendicaci/php${PHP_MAJOR_VERSION}:php${PHP_VERSION}
|
||||
environment:
|
||||
|
@ -86,7 +115,7 @@ steps:
|
|||
when:
|
||||
matrix:
|
||||
PHP_MAJOR_VERSION: 8.2
|
||||
PHP_VERSION: 8.2.16
|
||||
PHP_VERSION: 8.2.28
|
||||
repo:
|
||||
- friendica/friendica
|
||||
commands:
|
||||
|
|
|
@ -35,8 +35,9 @@ steps:
|
|||
volumes:
|
||||
- /tmp/drone-cache:/tmp/cache
|
||||
composer_install:
|
||||
image: friendicaci/php8.2:php8.2.16
|
||||
image: friendicaci/php8.2:php8.2.28
|
||||
commands:
|
||||
- mkdir addon # create empty addon folder to appease composer
|
||||
- export COMPOSER_HOME=.composer
|
||||
- composer validate
|
||||
- composer install --no-dev --optimize-autoloader
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
Version 2025.02 (unreleased)
|
||||
Friendica Core
|
||||
Deprecated bin/daemon in favor of bin/console daemon (PR 14642) [nupplaphil]
|
||||
Deprecated bin/jetstream in favor of bin/console jetstream (PR 14655) [nupplaphil]
|
||||
|
||||
Friendica Addons
|
||||
|
||||
Closed Issues
|
||||
|
||||
Version 2024.12 (2024-12-31)
|
||||
Friendica Core
|
||||
Updates to the translations AR, BG, CA, CS, DE, EO, ES, ET, FR, GD, HU, IS, IT, JA, NL, PL, RU, SV
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
2024.12
|
||||
2025.02-dev
|
||||
|
|
|
@ -44,44 +44,12 @@ if (php_sapi_name() !== 'cli') {
|
|||
exit();
|
||||
}
|
||||
|
||||
use Dice\Dice;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Logger\Capability\LogChannel;
|
||||
use Friendica\Security\ExAuth;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
if (sizeof($_SERVER["argv"]) == 0) {
|
||||
die();
|
||||
}
|
||||
|
||||
$directory = dirname($_SERVER["argv"][0]);
|
||||
|
||||
if (substr($directory, 0, 1) != DIRECTORY_SEPARATOR) {
|
||||
$directory = $_SERVER["PWD"] . DIRECTORY_SEPARATOR . $directory;
|
||||
}
|
||||
|
||||
$directory = realpath($directory . DIRECTORY_SEPARATOR . "..");
|
||||
|
||||
chdir($directory);
|
||||
chdir(dirname(__DIR__));
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
|
||||
/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */
|
||||
$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class);
|
||||
$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies'));
|
||||
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => [LogChannel::AUTH_JABBERED]]);
|
||||
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
|
||||
|
||||
\Friendica\DI::init($dice);
|
||||
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
|
||||
$app = \Friendica\App::fromContainer($container);
|
||||
|
||||
// Check the database structure and possibly fixes it
|
||||
\Friendica\Core\Update::check(\Friendica\DI::basePath(), true);
|
||||
|
||||
$appMode = $dice->create(Mode::class);
|
||||
|
||||
if ($appMode->isNormal()) {
|
||||
/** @var ExAuth $oAuth */
|
||||
$oAuth = $dice->create(ExAuth::class);
|
||||
$oAuth->readStdin();
|
||||
}
|
||||
$app->processEjabberd($_SERVER);
|
||||
|
|
Binary file not shown.
|
@ -1,14 +1,14 @@
|
|||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
dir=$(cd "${0%[/\\]*}" > /dev/null; pwd)
|
||||
dir=$(cd "$(dirname "$0")" > /dev/null 2>&1; pwd)
|
||||
|
||||
if [[ -d /proc/cygdrive && $(which php) == $(readlink -n /proc/cygdrive)/* ]]; then
|
||||
if [ -d /proc/cygdrive ] && [ "$(which php)" = "$(readlink -n /proc/cygdrive)/*" ]; then
|
||||
# We are in Cygwin using Windows php, so the path must be translated
|
||||
dir=$(cygpath -m "$dir");
|
||||
dir=$(cygpath -m "$dir")
|
||||
fi
|
||||
|
||||
php "${dir}/console.php" "$@"
|
||||
|
|
|
@ -13,21 +13,13 @@ if (php_sapi_name() !== 'cli') {
|
|||
exit();
|
||||
}
|
||||
|
||||
use Dice\Dice;
|
||||
use Friendica\Core\Logger\Capability\LogChannel;
|
||||
use Friendica\DI;
|
||||
use Psr\Log\LoggerInterface;
|
||||
// Ensure that te console is executed from the base path of the installation
|
||||
chdir(dirname(__DIR__));
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
|
||||
/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */
|
||||
$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class);
|
||||
$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies'));
|
||||
$dice = $dice->addRule(LoggerInterface::class, ['constructParams' => [LogChannel::CONSOLE]]);
|
||||
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
|
||||
|
||||
/// @fixme Necessary until Hooks inside the Logger can get loaded without the DI-class
|
||||
DI::init($dice);
|
||||
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
|
||||
$app = \Friendica\App::fromContainer($container);
|
||||
|
||||
(new Friendica\Core\Console($dice, $argv))->execute();
|
||||
$app->processConsole($_SERVER);
|
||||
|
|
231
bin/daemon.php
231
bin/daemon.php
|
@ -5,6 +5,8 @@
|
|||
* SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* @deprecated 2025.02 use `bin/console.php daemon` instead
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -17,231 +19,20 @@ if (php_sapi_name() !== 'cli') {
|
|||
exit();
|
||||
}
|
||||
|
||||
use Dice\Dice;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Update;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
// Get options
|
||||
$shortopts = 'f';
|
||||
$longopts = ['foreground'];
|
||||
$options = getopt($shortopts, $longopts);
|
||||
|
||||
// Ensure that daemon.php is executed from the base path of the installation
|
||||
if (!file_exists('index.php') && (sizeof($_SERVER['argv']) != 0)) {
|
||||
$directory = dirname($_SERVER['argv'][0]);
|
||||
|
||||
if (substr($directory, 0, 1) != '/') {
|
||||
$directory = $_SERVER['PWD'] . '/' . $directory;
|
||||
}
|
||||
$directory = realpath($directory . '/..');
|
||||
|
||||
chdir($directory);
|
||||
}
|
||||
chdir(dirname(__DIR__));
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
|
||||
/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */
|
||||
$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class);
|
||||
$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies'));
|
||||
$dice = $dice->addRule(LoggerInterface::class, ['constructParams' => [Logger\Capability\LogChannel::DAEMON]]);
|
||||
fwrite(STDOUT, '`bin/daemon.php` is deprecated since 2025.02 and will be removed in 5 months, please use `bin/console.php daemon` instead.' . \PHP_EOL);
|
||||
|
||||
DI::init($dice);
|
||||
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
|
||||
// BC: Add console command as second argument
|
||||
$argv = $_SERVER['argv'] ?? [];
|
||||
array_splice($argv, 1, 0, "daemon");
|
||||
$_SERVER['argv'] = $argv;
|
||||
|
||||
if (DI::mode()->isInstall()) {
|
||||
die("Friendica isn't properly installed yet.\n");
|
||||
}
|
||||
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
|
||||
|
||||
DI::mode()->setExecutor(Mode::DAEMON);
|
||||
$app = \Friendica\App::fromContainer($container);
|
||||
|
||||
DI::config()->reload();
|
||||
|
||||
if (empty(DI::config()->get('system', 'pidfile'))) {
|
||||
die(<<<TXT
|
||||
Please set system.pidfile in config/local.config.php. For example:
|
||||
|
||||
'system' => [
|
||||
'pidfile' => '/path/to/daemon.pid',
|
||||
],
|
||||
TXT
|
||||
);
|
||||
}
|
||||
|
||||
$pidfile = DI::config()->get('system', 'pidfile');
|
||||
|
||||
if (in_array('start', $_SERVER['argv'])) {
|
||||
$mode = 'start';
|
||||
}
|
||||
|
||||
if (in_array('stop', $_SERVER['argv'])) {
|
||||
$mode = 'stop';
|
||||
}
|
||||
|
||||
if (in_array('status', $_SERVER['argv'])) {
|
||||
$mode = 'status';
|
||||
}
|
||||
|
||||
$foreground = array_key_exists('f', $options) || array_key_exists('foreground', $options);
|
||||
|
||||
if (!isset($mode)) {
|
||||
die("Please use either 'start', 'stop' or 'status'.\n");
|
||||
}
|
||||
|
||||
if (empty($_SERVER['argv'][0])) {
|
||||
die("Unexpected script behaviour. This message should never occur.\n");
|
||||
}
|
||||
|
||||
$pid = null;
|
||||
|
||||
if (is_readable($pidfile)) {
|
||||
$pid = intval(file_get_contents($pidfile));
|
||||
}
|
||||
|
||||
if (empty($pid) && in_array($mode, ['stop', 'status'])) {
|
||||
DI::keyValue()->set('worker_daemon_mode', false);
|
||||
die("Pidfile wasn't found. Is the daemon running?\n");
|
||||
}
|
||||
|
||||
if ($mode == 'status') {
|
||||
if (posix_kill($pid, 0)) {
|
||||
die("Daemon process $pid is running.\n");
|
||||
}
|
||||
|
||||
unlink($pidfile);
|
||||
|
||||
DI::keyValue()->set('worker_daemon_mode', false);
|
||||
die("Daemon process $pid isn't running.\n");
|
||||
}
|
||||
|
||||
if ($mode == 'stop') {
|
||||
posix_kill($pid, SIGTERM);
|
||||
|
||||
unlink($pidfile);
|
||||
|
||||
Logger::notice('Worker daemon process was killed', ['pid' => $pid]);
|
||||
|
||||
DI::keyValue()->set('worker_daemon_mode', false);
|
||||
die("Worker daemon process $pid was killed.\n");
|
||||
}
|
||||
|
||||
if (!empty($pid) && posix_kill($pid, 0)) {
|
||||
die("Daemon process $pid is already running.\n");
|
||||
}
|
||||
|
||||
Logger::notice('Starting worker daemon.', ['pid' => $pid]);
|
||||
|
||||
if (!$foreground) {
|
||||
echo "Starting worker daemon.\n";
|
||||
|
||||
DBA::disconnect();
|
||||
|
||||
// Fork a daemon process
|
||||
$pid = pcntl_fork();
|
||||
if ($pid == -1) {
|
||||
echo "Daemon couldn't be forked.\n";
|
||||
Logger::warning('Could not fork daemon');
|
||||
exit(1);
|
||||
} elseif ($pid) {
|
||||
// The parent process continues here
|
||||
if (!file_put_contents($pidfile, $pid)) {
|
||||
echo "Pid file wasn't written.\n";
|
||||
Logger::warning('Could not store pid file');
|
||||
posix_kill($pid, SIGTERM);
|
||||
exit(1);
|
||||
}
|
||||
echo 'Child process started with pid ' . $pid . ".\n";
|
||||
Logger::notice('Child process started', ['pid' => $pid]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// We now are in the child process
|
||||
register_shutdown_function('shutdown');
|
||||
|
||||
// Make the child the main process, detach it from the terminal
|
||||
if (posix_setsid() < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Closing all existing connections with the outside
|
||||
fclose(STDIN);
|
||||
|
||||
// And now connect the database again
|
||||
DBA::connect();
|
||||
}
|
||||
|
||||
DI::keyValue()->set('worker_daemon_mode', true);
|
||||
|
||||
// Just to be sure that this script really runs endlessly
|
||||
set_time_limit(0);
|
||||
|
||||
$wait_interval = intval(DI::config()->get('system', 'cron_interval', 5)) * 60;
|
||||
|
||||
$do_cron = true;
|
||||
$last_cron = 0;
|
||||
|
||||
// Now running as a daemon.
|
||||
while (true) {
|
||||
// Check the database structure and possibly fixes it
|
||||
Update::check(DI::basePath(), true);
|
||||
|
||||
if (!$do_cron && ($last_cron + $wait_interval) < time()) {
|
||||
Logger::info('Forcing cron worker call.', ['pid' => $pid]);
|
||||
$do_cron = true;
|
||||
}
|
||||
|
||||
if ($do_cron || (!DI::system()->isMaxLoadReached() && Worker::entriesExists() && Worker::isReady())) {
|
||||
Worker::spawnWorker($do_cron);
|
||||
} else {
|
||||
Logger::info('Cool down for 5 seconds', ['pid' => $pid]);
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
if ($do_cron) {
|
||||
// We force a reconnect of the database connection.
|
||||
// This is done to ensure that the connection don't get lost over time.
|
||||
DBA::reconnect();
|
||||
|
||||
$last_cron = time();
|
||||
}
|
||||
|
||||
$start = time();
|
||||
Logger::info('Sleeping', ['pid' => $pid, 'until' => gmdate(DateTimeFormat::MYSQL, $start + $wait_interval)]);
|
||||
|
||||
do {
|
||||
$seconds = (time() - $start);
|
||||
|
||||
// logarithmic wait time calculation.
|
||||
// Background: After jobs had been started, they often fork many workers.
|
||||
// To not waste too much time, the sleep period increases.
|
||||
$arg = (($seconds + 1) / ($wait_interval / 9)) + 1;
|
||||
$sleep = min(1000000, round(log10($arg) * 1000000, 0));
|
||||
usleep($sleep);
|
||||
|
||||
$pid = pcntl_waitpid(-1, $status, WNOHANG);
|
||||
if ($pid > 0) {
|
||||
Logger::info('Children quit via pcntl_waitpid', ['pid' => $pid, 'status' => $status]);
|
||||
}
|
||||
|
||||
$timeout = ($seconds >= $wait_interval);
|
||||
} while (!$timeout && !Worker\IPC::JobsExists());
|
||||
|
||||
if ($timeout) {
|
||||
$do_cron = true;
|
||||
Logger::info('Woke up after $wait_interval seconds.', ['pid' => $pid, 'sleep' => $wait_interval]);
|
||||
} else {
|
||||
$do_cron = false;
|
||||
Logger::info('Worker jobs are calling to be forked.', ['pid' => $pid]);
|
||||
}
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
posix_kill(posix_getpid(), SIGTERM);
|
||||
posix_kill(posix_getpid(), SIGHUP);
|
||||
}
|
||||
$app->processConsole($_SERVER);
|
||||
|
|
24
bin/dev/fix-codestyle.sh
Executable file
24
bin/dev/fix-codestyle.sh
Executable file
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
# SPDX-FileCopyrightText: 2010-2025 the Friendica project
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# this script checks or fixes php-files, based on the php-cs rules
|
||||
#
|
||||
# You can use the following variables:
|
||||
# COMMAND ... the php-cs command to execute (default is "check --diff")
|
||||
# TARGET_BRANCH ... set the target branch for the current branch to create a diff between them
|
||||
#
|
||||
##
|
||||
|
||||
COMMAND=${COMMAND:-"check --diff"}
|
||||
|
||||
if [ -n "${TARGET_BRANCH}" ]; then
|
||||
CHANGED_FILES="$(git diff --name-only --diff-filter=ACMRTUXB "$(git ls-remote -q | grep refs/heads/"${TARGET_BRANCH}"$ | awk '{print $1}' | xargs git rev-parse )".."$(git rev-parse HEAD)")";
|
||||
else
|
||||
CHANGED_FILES="$(git diff --name-only --diff-filter=ACMRTUXB "$(git rev-parse HEAD)")";
|
||||
fi
|
||||
|
||||
EXTRA_ARGS=$(printf -- '--path-mode=intersection\n--\n%s' "${CHANGED_FILES}");
|
||||
|
||||
./bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer ${COMMAND} --config=.php-cs-fixer.dist.php -v --using-cache=no ${EXTRA_ARGS}
|
|
@ -129,7 +129,7 @@ bin/console user password "$USER_NICK" "$USER_PASSW"
|
|||
# create cronjob - activate if you have enough memory in you dev VM
|
||||
# cronjob runs as www-data user
|
||||
echo ">>> Installing cronjob"
|
||||
echo "*/10 * * * * www-data cd /vagrant; /usr/bin/php bin/worker.php" >> /etc/cron.d/friendica
|
||||
echo "*/10 * * * * www-data cd /vagrant; /usr/bin/php bin/console.php worker" >> /etc/cron.d/friendica
|
||||
|
||||
# friendica needs write access to /tmp
|
||||
chmod 777 /tmp
|
||||
|
|
|
@ -6,179 +6,28 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* @deprecated 2025.02 use `bin/console.php jetstream` instead
|
||||
*/
|
||||
|
||||
use Dice\Dice;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Friendica\Protocol\ATProtocol\Jetstream;
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Ensure that Jetstream.php is executed from the base path of the installation
|
||||
if (!file_exists('index.php') && (sizeof((array)$_SERVER['argv']) != 0)) {
|
||||
$directory = dirname($_SERVER['argv'][0]);
|
||||
|
||||
if (substr($directory, 0, 1) != '/') {
|
||||
$directory = $_SERVER['PWD'] . '/' . $directory;
|
||||
}
|
||||
$directory = realpath($directory . '/..');
|
||||
|
||||
chdir($directory);
|
||||
}
|
||||
chdir(dirname(__DIR__));
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
|
||||
/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */
|
||||
$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class);
|
||||
$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies'));
|
||||
$dice = $dice->addRule(LoggerInterface::class, ['constructParams' => [Logger\Capability\LogChannel::DAEMON]]);
|
||||
fwrite(STDOUT, '`bin/jetstream.php` is deprecated since 2025.02 and will be removed in 5 months, please use `bin/console.php jetstream` instead.' . \PHP_EOL);
|
||||
|
||||
DI::init($dice);
|
||||
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
|
||||
Addon::loadAddons();
|
||||
Hook::loadHooks();
|
||||
DI::config()->reload();
|
||||
// BC: Add console command as second argument
|
||||
$argv = $_SERVER['argv'] ?? [];
|
||||
array_splice($argv, 1, 0, "jetstream");
|
||||
$_SERVER['argv'] = $argv;
|
||||
|
||||
if (DI::mode()->isInstall()) {
|
||||
die("Friendica isn't properly installed yet.\n");
|
||||
}
|
||||
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
|
||||
|
||||
if (empty(DI::config()->get('jetstream', 'pidfile'))) {
|
||||
die(<<<TXT
|
||||
Please set jetstream.pidfile in config/local.config.php. For example:
|
||||
$app = \Friendica\App::fromContainer($container);
|
||||
|
||||
'jetstream' => [
|
||||
'pidfile' => '/path/to/jetstream.pid',
|
||||
],
|
||||
TXT);
|
||||
}
|
||||
|
||||
if (!Addon::isEnabled('bluesky')) {
|
||||
die("Bluesky has to be enabled.\n");
|
||||
}
|
||||
|
||||
$pidfile = DI::config()->get('jetstream', 'pidfile');
|
||||
|
||||
if (in_array('start', (array)$_SERVER['argv'])) {
|
||||
$mode = 'start';
|
||||
}
|
||||
|
||||
if (in_array('stop', (array)$_SERVER['argv'])) {
|
||||
$mode = 'stop';
|
||||
}
|
||||
|
||||
if (in_array('status', (array)$_SERVER['argv'])) {
|
||||
$mode = 'status';
|
||||
}
|
||||
|
||||
if (!isset($mode)) {
|
||||
die("Please use either 'start', 'stop' or 'status'.\n");
|
||||
}
|
||||
|
||||
// Get options
|
||||
$shortopts = 'f';
|
||||
$longopts = ['foreground'];
|
||||
$options = getopt($shortopts, $longopts);
|
||||
|
||||
$foreground = array_key_exists('f', $options) || array_key_exists('foreground', $options);
|
||||
|
||||
if (empty($_SERVER['argv'][0])) {
|
||||
die("Unexpected script behaviour. This message should never occur.\n");
|
||||
}
|
||||
|
||||
$pid = null;
|
||||
|
||||
if (is_readable($pidfile)) {
|
||||
$pid = intval(file_get_contents($pidfile));
|
||||
}
|
||||
|
||||
if (empty($pid) && in_array($mode, ['stop', 'status'])) {
|
||||
die("Pidfile wasn't found. Is jetstream running?\n");
|
||||
}
|
||||
|
||||
if ($mode == 'status') {
|
||||
if (posix_kill($pid, 0)) {
|
||||
die("Jetstream process $pid is running.\n");
|
||||
}
|
||||
|
||||
unlink($pidfile);
|
||||
|
||||
die("Jetstream process $pid isn't running.\n");
|
||||
}
|
||||
|
||||
if ($mode == 'stop') {
|
||||
posix_kill($pid, SIGTERM);
|
||||
|
||||
unlink($pidfile);
|
||||
|
||||
Logger::notice('Jetstream process was killed', ['pid' => $pid]);
|
||||
|
||||
die("Jetstream process $pid was killed.\n");
|
||||
}
|
||||
|
||||
if (!empty($pid) && posix_kill($pid, 0)) {
|
||||
die("Jetstream process $pid is already running.\n");
|
||||
}
|
||||
|
||||
Logger::notice('Starting jetstream daemon.', ['pid' => $pid]);
|
||||
|
||||
if (!$foreground) {
|
||||
echo "Starting jetstream daemon.\n";
|
||||
|
||||
DBA::disconnect();
|
||||
|
||||
// Fork a daemon process
|
||||
$pid = pcntl_fork();
|
||||
if ($pid == -1) {
|
||||
echo "Daemon couldn't be forked.\n";
|
||||
Logger::warning('Could not fork daemon');
|
||||
exit(1);
|
||||
} elseif ($pid) {
|
||||
// The parent process continues here
|
||||
if (!file_put_contents($pidfile, $pid)) {
|
||||
echo "Pid file wasn't written.\n";
|
||||
Logger::warning('Could not store pid file');
|
||||
posix_kill($pid, SIGTERM);
|
||||
exit(1);
|
||||
}
|
||||
echo 'Child process started with pid ' . $pid . ".\n";
|
||||
Logger::notice('Child process started', ['pid' => $pid]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// We now are in the child process
|
||||
register_shutdown_function('shutdown');
|
||||
|
||||
// Make the child the main process, detach it from the terminal
|
||||
if (posix_setsid() < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Closing all existing connections with the outside
|
||||
fclose(STDIN);
|
||||
|
||||
// And now connect the database again
|
||||
DBA::connect();
|
||||
}
|
||||
|
||||
// Just to be sure that this script really runs endlessly
|
||||
set_time_limit(0);
|
||||
|
||||
// Now running as a daemon.
|
||||
$jetstream = $dice->create(Jetstream::class);
|
||||
$jetstream->listen();
|
||||
|
||||
function shutdown()
|
||||
{
|
||||
posix_kill(posix_getpid(), SIGTERM);
|
||||
posix_kill(posix_getpid(), SIGHUP);
|
||||
}
|
||||
$app->processConsole($_SERVER);
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
set -eo pipefail
|
||||
set -e
|
||||
|
||||
function resolve {
|
||||
if [ "$(uname)" == "Darwin" ]
|
||||
# Custom function to handle pipefail behavior
|
||||
pipefail() {
|
||||
local cmd="$1"
|
||||
shift
|
||||
{ eval "$cmd"; } || exit 1
|
||||
}
|
||||
|
||||
resolve() {
|
||||
if [ "$(uname)" = "Darwin" ]
|
||||
then
|
||||
realpath "$1"
|
||||
else
|
||||
|
@ -17,7 +24,7 @@ function resolve {
|
|||
|
||||
FULLPATH=$(dirname "$(resolve "$0")")
|
||||
|
||||
if [ "$1" == "--help" ] || [ "$1" == "-h" ]
|
||||
if [ "$1" = "--help" ] || [ "$1" = "-h" ]
|
||||
then
|
||||
echo "$(basename "$(resolve "$0")") [options]"
|
||||
echo
|
||||
|
@ -28,15 +35,15 @@ fi
|
|||
|
||||
MODE='default'
|
||||
ADDONNAME=
|
||||
if [ "$1" == "--addon" ] || [ "$1" == "-a" ]
|
||||
if [ "$1" = "--addon" ] || [ "$1" = "-a" ]
|
||||
then
|
||||
MODE='addon'
|
||||
if [ -z "$2" ]; then echo -e "ERROR: missing addon name\n\nrun_xgettext.sh -a <addonname>"; exit 1; fi
|
||||
if [ -z "$2" ]; then echo "ERROR: missing addon name\n\nrun_xgettext.sh -a <addonname>"; exit 1; fi
|
||||
ADDONNAME=$2
|
||||
if [ ! -d "$FULLPATH/../addon/$ADDONNAME" ]; then echo "ERROR: addon '$ADDONNAME' not found"; exit 2; fi
|
||||
fi
|
||||
|
||||
if [ "$1" == "--single" ] || [ "$1" == "-s" ]
|
||||
if [ "$1" = "--single" ] || [ "$1" = "-s" ]
|
||||
then
|
||||
MODE='single'
|
||||
fi
|
||||
|
@ -70,7 +77,6 @@ case "$MODE" in
|
|||
;;
|
||||
esac
|
||||
|
||||
|
||||
KEYWORDS="-k -kt -ktt:1,2"
|
||||
|
||||
echo "Extract strings to $OUTFILE.."
|
||||
|
@ -79,13 +85,13 @@ echo "Extract strings to $OUTFILE.."
|
|||
# shellcheck disable=SC2086 # $FINDOPTS is meant to be split
|
||||
find_result=$(find "$FINDSTARTDIR" $FINDOPTS -name "*.php" -type f | LC_ALL=C sort -s)
|
||||
|
||||
total_files=$(wc -l <<< "${find_result}")
|
||||
total_files=$(echo "${find_result}" | wc -l)
|
||||
|
||||
count=1
|
||||
for file in $find_result
|
||||
do
|
||||
echo -ne " \r"
|
||||
echo -ne "Reading file $count/$total_files..."
|
||||
printf " \r"
|
||||
printf "Reading file %d/%d..." "$count" "$total_files"
|
||||
|
||||
# On Windows, find still outputs the name of pruned folders
|
||||
if [ ! -d "$file" ]
|
||||
|
@ -94,9 +100,8 @@ do
|
|||
xgettext $KEYWORDS --no-wrap -j -o "$OUTFILE" --from-code=UTF-8 "$file" || exit 1
|
||||
sed -i.bkp "s/CHARSET/UTF-8/g" "$OUTFILE"
|
||||
fi
|
||||
(( count++ ))
|
||||
count=$((count + 1))
|
||||
done
|
||||
echo -ne "\n"
|
||||
|
||||
echo "Interpolate metadata.."
|
||||
|
||||
|
@ -119,7 +124,7 @@ case "$MODE" in
|
|||
;;
|
||||
esac
|
||||
|
||||
if [ "" != "$1" ] && [ "$MODE" == "default" ]
|
||||
if [ -n "$1" ] && [ "$MODE" = "default" ]
|
||||
then
|
||||
UPDATEFILE="$(resolve "${FULLPATH}/$1")"
|
||||
echo "Merging new strings to $UPDATEFILE.."
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* Starts the background processing
|
||||
*
|
||||
* @deprecated 2025.02 use `bin/console.php worker` instead
|
||||
*/
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
|
@ -14,66 +16,20 @@ if (php_sapi_name() !== 'cli') {
|
|||
exit();
|
||||
}
|
||||
|
||||
use Dice\Dice;
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Logger\Capability\LogChannel;
|
||||
use Friendica\Core\Update;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\DI;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
// Get options
|
||||
$shortopts = 'sn';
|
||||
$longopts = ['spawn', 'no_cron'];
|
||||
$options = getopt($shortopts, $longopts);
|
||||
|
||||
// Ensure that worker.php is executed from the base path of the installation
|
||||
if (!file_exists("index.php") && (sizeof($_SERVER["argv"]) != 0)) {
|
||||
$directory = dirname($_SERVER["argv"][0]);
|
||||
|
||||
if (substr($directory, 0, 1) != '/') {
|
||||
$directory = $_SERVER["PWD"] . '/' . $directory;
|
||||
}
|
||||
$directory = realpath($directory . '/..');
|
||||
|
||||
chdir($directory);
|
||||
}
|
||||
chdir(dirname(__DIR__));
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
|
||||
/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */
|
||||
$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class);
|
||||
$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies'));
|
||||
$dice = $dice->addRule(LoggerInterface::class, ['constructParams' => [LogChannel::WORKER]]);
|
||||
fwrite(STDOUT, '`bin/worker.php` is deprecated since 2025.02 and will be removed in 5 months, please use `bin/console.php worker` instead.' . \PHP_EOL);
|
||||
|
||||
DI::init($dice);
|
||||
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
|
||||
// BC: Add console command as second argument
|
||||
$argv = $_SERVER['argv'] ?? [];
|
||||
array_splice($argv, 1, 0, "worker");
|
||||
$_SERVER['argv'] = $argv;
|
||||
|
||||
DI::mode()->setExecutor(Mode::WORKER);
|
||||
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
|
||||
|
||||
// Check the database structure and possibly fixes it
|
||||
Update::check(DI::basePath(), true);
|
||||
$app = \Friendica\App::fromContainer($container);
|
||||
|
||||
// Quit when in maintenance
|
||||
if (!DI::mode()->has(App\Mode::MAINTENANCEDISABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$spawn = array_key_exists('s', $options) || array_key_exists('spawn', $options);
|
||||
|
||||
if ($spawn) {
|
||||
Worker::spawnWorker();
|
||||
exit();
|
||||
}
|
||||
|
||||
$run_cron = !array_key_exists('n', $options) && !array_key_exists('no_cron', $options);
|
||||
|
||||
$process = DI::process()->create(getmypid(), basename(__FILE__));
|
||||
|
||||
Worker::processQueue($run_cron, $process);
|
||||
|
||||
Worker::unclaimProcess($process);
|
||||
|
||||
DI::process()->delete($process);
|
||||
$app->processConsole($_SERVER);
|
||||
|
|
|
@ -29,13 +29,14 @@
|
|||
"ext-xml": "*",
|
||||
"asika/simple-console": "^1.0",
|
||||
"bacon/bacon-qr-code": "^2.0.0",
|
||||
"bower-asset/base64": "^1.0",
|
||||
"divineomega/password_exposed": "^3",
|
||||
"enyo/dropzone": "^5.9",
|
||||
"ezyang/htmlpurifier": "^4.7",
|
||||
"friendica/json-ld": "^1.0",
|
||||
"geekwright/po": "^2.0",
|
||||
"guzzlehttp/guzzle": "^7",
|
||||
"guzzlehttp/oauth-subscriber": "^0.6",
|
||||
"guzzlehttp/oauth-subscriber": "^0.8",
|
||||
"kornrunner/blurhash": "^1.2",
|
||||
"league/html-to-markdown": "^4.8",
|
||||
"level-2/dice": "^4",
|
||||
|
@ -46,37 +47,38 @@
|
|||
"minishlink/web-push": "^6.0",
|
||||
"mobiledetect/mobiledetectlib": "^3.74",
|
||||
"nikic/fast-route": "^1.3",
|
||||
"paragonie/hidden-string": "^1.0",
|
||||
"patrickschur/language-detection": "^5.0.0",
|
||||
"pear/console_table": "^1.3",
|
||||
"phpseclib/phpseclib": "^3.0",
|
||||
"pragmarx/google2fa": "^5.0",
|
||||
"pragmarx/recovery": "^0.2",
|
||||
"psr/clock": "^1.0",
|
||||
"psr/container": "^2.0",
|
||||
"psr/log": "^1.1",
|
||||
"seld/cli-prompt": "^1.0",
|
||||
"smarty/smarty": "^4",
|
||||
"ua-parser/uap-php": "^3.9",
|
||||
"xemlock/htmlpurifier-html5": "^0.1.11",
|
||||
"fxp/composer-asset-plugin": "^1.4",
|
||||
"bower-asset/base64": "^1.0",
|
||||
"bower-asset/chart-js": "^2.8",
|
||||
"bower-asset/dompurify": "^1.0",
|
||||
"bower-asset/fork-awesome": "^1.1",
|
||||
"npm-asset/chart.js": "^2.8",
|
||||
"npm-asset/cropperjs": "1.2.2",
|
||||
"npm-asset/dompurify": "^1.0",
|
||||
"npm-asset/es-jquery-sortable": "^0.9.13",
|
||||
"npm-asset/fork-awesome": "^1.1",
|
||||
"npm-asset/fullcalendar": "^3.10",
|
||||
"npm-asset/imagesloaded": "4.1.4",
|
||||
"npm-asset/jgrowl": "^1.4",
|
||||
"npm-asset/jquery": "^2.0",
|
||||
"npm-asset/jquery-colorbox": "^1.6",
|
||||
"npm-asset/jquery-datetimepicker": "^2.5",
|
||||
"npm-asset/jgrowl": "^1.4",
|
||||
"npm-asset/moment": "^2.24",
|
||||
"npm-asset/perfect-scrollbar": "0.6.16",
|
||||
"npm-asset/textcomplete": "^0.18.2",
|
||||
"npm-asset/typeahead.js": "^0.11.1",
|
||||
"textalk/websocket": "^1.6"
|
||||
"oomphinc/composer-installers-extender": "^2.0",
|
||||
"paragonie/hidden-string": "^1.0",
|
||||
"patrickschur/language-detection": "^5.0.0",
|
||||
"pear/console_table": "^1.3",
|
||||
"phpseclib/phpseclib": "^3.0",
|
||||
"phrity/websocket": "^1.7",
|
||||
"pragmarx/google2fa": "^5.0",
|
||||
"pragmarx/recovery": "^0.2",
|
||||
"psr/clock": "^1.0",
|
||||
"psr/container": "^1.1|^2.0",
|
||||
"psr/event-dispatcher": "^1.0",
|
||||
"psr/log": "^1.1",
|
||||
"seld/cli-prompt": "^1.0",
|
||||
"smarty/smarty": "^4",
|
||||
"symfony/event-dispatcher": "^5.4",
|
||||
"ua-parser/uap-php": "^3.9",
|
||||
"xemlock/htmlpurifier-html5": "^0.1.11"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-imagick": "For faster image processing",
|
||||
|
@ -88,13 +90,20 @@
|
|||
{
|
||||
"type": "vcs",
|
||||
"url": "https://git.friendi.ca/friendica/php-json-ld"
|
||||
},
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://asset-packagist.org"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Friendica\\": "src/",
|
||||
"Friendica\\Addon\\": "addon/"
|
||||
}
|
||||
"Friendica\\": "src/"
|
||||
},
|
||||
"classmap": ["addon/"],
|
||||
"exclude-from-classmap": [
|
||||
"addon/*/vendor/"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
|
@ -105,14 +114,22 @@
|
|||
"platform": {
|
||||
"php": "7.4"
|
||||
},
|
||||
"sort-packages": true,
|
||||
"autoloader-suffix": "Friendica",
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"fxp-asset": {
|
||||
"installer-paths": {
|
||||
"npm-asset-library": "view/asset",
|
||||
"bower-asset-library": "view/asset"
|
||||
"allow-plugins": {
|
||||
"composer/installers": true,
|
||||
"oomphinc/composer-installers-extender": true,
|
||||
"php-http/discovery": false
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"installer-types": ["bower-asset", "npm-asset"],
|
||||
"installer-paths": {
|
||||
"view/asset/{$name}/": [
|
||||
"type:bower-asset",
|
||||
"type:npm-asset"
|
||||
]
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
|
@ -133,15 +150,24 @@
|
|||
]
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.3",
|
||||
"dms/phpunit-arraysubset-asserts": "^0.3.1",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"phpunit/phpunit": "^9",
|
||||
"dms/phpunit-arraysubset-asserts": "^0.3.1"
|
||||
"mockery/mockery": "^1.3",
|
||||
"php-mock/php-mock-mockery": "^1.5",
|
||||
"php-mock/php-mock-phpunit": "^2.10",
|
||||
"phpmd/phpmd": "^2.15",
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"phpunit/phpunit": "^9"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit",
|
||||
"test:unit": "phpunit -c tests/phpunit.xml --testsuite unit",
|
||||
"phpmd": "phpmd src/ text .phpmd-ruleset.xml --color --cache",
|
||||
"phpstan": "phpstan analyze --memory-limit 1024M --configuration .phpstan.neon",
|
||||
"phpstan-addons": "phpstan analyze --memory-limit 1024M --configuration .phpstan-addons.neon",
|
||||
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l",
|
||||
"docker:translate": "docker run --rm -v $PWD:/data -w /data friendicaci/transifex bin/run_xgettext.sh",
|
||||
"lang:recreate": "bin/run_xgettext.sh",
|
||||
"cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer",
|
||||
"cs:check": [
|
||||
"@cs:install",
|
||||
|
@ -150,6 +176,9 @@
|
|||
"cs:fix": [
|
||||
"@cs:install",
|
||||
"bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix"
|
||||
]
|
||||
],
|
||||
"cs:fix-develop": "TARGET_BRANCH=develop COMMAND=fix bin/dev/fix-codestyle.sh",
|
||||
"db:update-structure": "bin/console.php dbstructure dumpsql > database.sql",
|
||||
"install:prod": "@composer install -o --no-dev"
|
||||
}
|
||||
}
|
||||
|
|
3143
composer.lock
generated
3143
composer.lock
generated
File diff suppressed because it is too large
Load diff
17
database.sql
17
database.sql
|
@ -1,6 +1,6 @@
|
|||
-- ------------------------------------------
|
||||
-- Friendica 2024.12 (Interrupted Fern)
|
||||
-- DB_UPDATE_VERSION 1576
|
||||
-- Friendica 2025.02-dev (Interrupted Fern)
|
||||
-- DB_UPDATE_VERSION 1580
|
||||
-- ------------------------------------------
|
||||
|
||||
|
||||
|
@ -41,10 +41,13 @@ CREATE TABLE IF NOT EXISTS `gserver` (
|
|||
`blocked` boolean COMMENT 'Server is blocked',
|
||||
`failed` boolean COMMENT 'Connection failed',
|
||||
`next_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT 'Next connection request',
|
||||
`redirect-gsid` int unsigned COMMENT 'Target Gserver id in case of a redirect',
|
||||
PRIMARY KEY(`id`),
|
||||
UNIQUE INDEX `nurl` (`nurl`(190)),
|
||||
INDEX `next_contact` (`next_contact`),
|
||||
INDEX `network` (`network`)
|
||||
INDEX `network` (`network`),
|
||||
INDEX `redirect-gsid` (`redirect-gsid`),
|
||||
FOREIGN KEY (`redirect-gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Global servers';
|
||||
|
||||
--
|
||||
|
@ -1438,6 +1441,9 @@ CREATE TABLE IF NOT EXISTS `post-media` (
|
|||
`publisher-url` varbinary(383) COMMENT 'URL of the publisher of the media',
|
||||
`publisher-name` varchar(255) COMMENT 'Name of the publisher of the media',
|
||||
`publisher-image` varbinary(383) COMMENT 'Image of the publisher of the media',
|
||||
`language` char(3) COMMENT 'Language information about this media in the ISO 639 format',
|
||||
`published` datetime COMMENT 'Publification date of this media',
|
||||
`modified` datetime COMMENT 'Modification date of this media',
|
||||
PRIMARY KEY(`id`),
|
||||
UNIQUE INDEX `uri-id-url` (`uri-id`,`url`(512)),
|
||||
INDEX `uri-id-id` (`uri-id`,`id`),
|
||||
|
@ -1609,7 +1615,7 @@ CREATE TABLE IF NOT EXISTS `post-user` (
|
|||
`psid` int unsigned COMMENT 'ID of the permission set of this post',
|
||||
PRIMARY KEY(`id`),
|
||||
UNIQUE INDEX `uid_uri-id` (`uid`,`uri-id`),
|
||||
INDEX `uri-id` (`uri-id`),
|
||||
INDEX `uri-id_origin_deleted` (`uri-id`,`origin`,`deleted`),
|
||||
INDEX `parent-uri-id` (`parent-uri-id`),
|
||||
INDEX `thr-parent-id` (`thr-parent-id`),
|
||||
INDEX `external-id` (`external-id`),
|
||||
|
@ -3809,7 +3815,8 @@ CREATE VIEW `pending-view` AS SELECT
|
|||
`contact`.`nick` AS `nick`
|
||||
FROM `register`
|
||||
INNER JOIN `contact` ON `register`.`uid` = `contact`.`uid`
|
||||
INNER JOIN `user` ON `register`.`uid` = `user`.`uid`;
|
||||
INNER JOIN `user` ON `register`.`uid` = `user`.`uid`
|
||||
WHERE `register`.`uid` != 0;
|
||||
|
||||
--
|
||||
-- VIEW tag-search-view
|
||||
|
|
|
@ -341,13 +341,13 @@ function samplestorage_storage_uninstall()
|
|||
DI::storageManager()->unregister(SampleStorageBackend::class);
|
||||
}
|
||||
|
||||
function samplestorage_storage_instance(App $a, array &$data)
|
||||
function samplestorage_storage_instance(AppHelper $appHelper, array &$data)
|
||||
{
|
||||
$config = new SampleStorageBackendConfig(DI::l10n(), DI::config());
|
||||
$data['storage'] = new SampleStorageBackendConfig($config->getFileName());
|
||||
}
|
||||
|
||||
function samplestorage_storage_config(App $a, array &$data)
|
||||
function samplestorage_storage_config(AppHelper $appHelper, array &$data)
|
||||
{
|
||||
$data['storage_config'] = new SampleStorageBackendConfig(DI::l10n(), DI::config());
|
||||
}
|
||||
|
|
|
@ -876,7 +876,7 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
|
|||
|
||||
### src/Content/ContactBlock.php
|
||||
|
||||
Hook::callAll('contact_block_end', $arr);
|
||||
Hook::callAll('contact_block_end', $text);
|
||||
|
||||
### src/Content/Text/BBCode.php
|
||||
|
||||
|
|
|
@ -156,16 +156,6 @@ $a->config['register_policy'] = REGISTER_CLOSED;
|
|||
'config' => [
|
||||
'register_policy' => \Friendica\Module\Register::CLOSED,
|
||||
],
|
||||
</pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
$a->path = "value";
|
||||
</pre></td>
|
||||
<td><pre>
|
||||
'system' => [
|
||||
'urlpath' => 'value',
|
||||
],
|
||||
</pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -62,7 +62,7 @@ If you want to have git automatically update the dependencies with composer, you
|
|||
}
|
||||
# `composer install` if the `composer.lock` file gets changed
|
||||
# to update all the php dependencies
|
||||
check_run composer.lock "bin/composer.phar install --no-dev"
|
||||
check_run composer.lock "bin/composer.phar install"
|
||||
|
||||
just place it into `.git/hooks/post-merge` and make it executable.
|
||||
|
||||
|
@ -156,3 +156,98 @@ If you are interested in improving those clients, please contact the developers
|
|||
* iOS: *currently no client*
|
||||
* SailfishOS: **Friendiy** [src](https://kirgroup.com/projects/fabrixxm/harbour-friendly) - developed by [Fabio](https://kirgroup.com/profile/fabrixxm/profile)
|
||||
* Windows: **Friendica Mobile** for Windows versions [before 8.1](http://windowsphone.com/s?appid=e3257730-c9cf-4935-9620-5261e3505c67) and [Windows 10](https://www.microsoft.com/store/apps/9nblggh0fhmn) - developed by [Gerhard Seeber](http://mozartweg.dyndns.org/friendica/profile/gerhard/profile)
|
||||
|
||||
## Backward compatibility
|
||||
|
||||
### Backward Compatibility Promise
|
||||
|
||||
Friendica can be extended by addons.
|
||||
These addons relies on many classes and conventions from Friendica.
|
||||
As developers our work on Friendica should not break things in the addons without giving the addon maintainers a chance to fix their addons.
|
||||
Our goal is to build trust for the addon maintainers but also allow Friendica developers to move on.
|
||||
This is called the Backward Compatibility Promise.
|
||||
|
||||
Inspired by the [Symonfy BC promise](https://symfony.com/doc/current/contributing/code/bc.html) we promise BC for every class, interface, trait, enum, function, constant, etc., but with the exception of:
|
||||
|
||||
- Classes, interfaces, traits, enums, functions, methods, properties and constants marked as `@internal` or `@private`
|
||||
- Extending or modifying any non-abstract class or method in any way
|
||||
- Extending or modifying a `final` class or method in any way
|
||||
- Calling `private` methods (via Reflection)
|
||||
- Accessing `private` properties (via Reflection)
|
||||
- Accessing `private` methods (via Reflection)
|
||||
- Accessing `private` constants (via Reflection)
|
||||
- New properties on overridden `protected` methods
|
||||
- Possible name collisions with new methods in an extended class (addon developers should prefix their custom methods in the extending classes in an appropriate way)
|
||||
- Dropping support for every PHP version that has reached end of life
|
||||
|
||||
### Deprecation and removing features
|
||||
|
||||
As the development goes by Friendica needs to get rid of old code and concepts.
|
||||
This will be done in 3 steps to give addon maintainers a chance to adjust their addons.
|
||||
|
||||
**1. Label deprecation**
|
||||
|
||||
If we as the Friendica maintainers decide to remove some functions, classes, interface, etc. we start this by adding a `@deprecated` PHPDoc note on the code.
|
||||
For instance the class `Friendica\Core\Logger` should be removed, so we add the following note with a possible replacement:
|
||||
|
||||
```php
|
||||
/**
|
||||
* Logger functions
|
||||
*
|
||||
* @deprecated 2025.02 Use constructor injection or `DI::logger()` instead
|
||||
*/
|
||||
class Logger {/* ... */}
|
||||
```
|
||||
|
||||
This way addon developers might be notified early by their IDE or other tools that the usage of the class is deprecated.
|
||||
In Friendica we can now start to replace all occurrences and usage of this class with the alternative.
|
||||
|
||||
The deprecation label COULD be remain over multiple releases.
|
||||
As long as the code that is labeled with `@deprecated` is used inside Friendica or the official addon repository, it SHOULD NOT be hard deprecated.
|
||||
|
||||
**2. Hard deprecation**
|
||||
|
||||
If the deprecated code is no longer used inside Friendica or the official addons it MUST be hard deprecated.
|
||||
The code MUST NOT be deleted.
|
||||
Starting from the next release, it MUST be stay for at least 5 months.
|
||||
Hard deprecated code COULD remain longer than 5 months, depending on when a release appears.
|
||||
Addon developer SHOULD NOT consider that they have more than 5 months to adjust their code.
|
||||
|
||||
Hard deprecation code means that the code triggers a muted `E_USER_DEPRECATION` error if it is called.
|
||||
For instance with the deprecated class `Friendica\Core\Logger` the call of every method should trigger an error:
|
||||
|
||||
```php
|
||||
/**
|
||||
* Logger functions
|
||||
*
|
||||
* @deprecated 2025.02 Use constructor injection or `DI::logger()` instead
|
||||
*/
|
||||
class Logger {
|
||||
public static function info(string $message, array $context = [])
|
||||
{
|
||||
@trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.05 and will be removed after 5 months, use constructor injection or `DI::logger()` instead.', E_USER_DEPRECATED);
|
||||
|
||||
self::getInstance()->info($message, $context);
|
||||
}
|
||||
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
This way the maintainer or users of addons will be notified in the logs that the addon will stop working in one of the next releases.
|
||||
The addon maintainer now has at least 5 months or at least one release to fix the deprecations.
|
||||
|
||||
Please note that the deprecation message contains the release that will be released next.
|
||||
In the example the code was hard deprecated with release `2025.05`, so it COULD be removed earliest with the `2025.11` release.
|
||||
|
||||
**3. Code Removing**
|
||||
|
||||
We promise BC for deprecated code for at least 5 months, starting from the release the deprecation was announced.
|
||||
After this time the deprecated code COULD be remove within the next release.
|
||||
|
||||
Breaking changes MUST be happen only in a new release but MUST be hard deprecated first.
|
||||
The BC promise refers only to releases, respective the `stable` branch.
|
||||
Deprecated code on other branches like `develop` or RC branches could be removed earlier.
|
||||
This is not a BC break as long as the release will be published 5 months after the hard deprecation.
|
||||
|
||||
If a release breaks BC without deprecation or earlier than 5 months, this SHOULD considered as a bug and BC SHOULD be restored in a bugfix release.
|
||||
|
|
11
doc/FAQ.md
11
doc/FAQ.md
|
@ -177,15 +177,18 @@ Example: Friendica Support
|
|||
Friendica supports [Mastodon API](help/API-Mastodon) and [Twitter API | gnusocial](help/api).
|
||||
This means you can use some of the Mastodon and Twitter clients for Friendica.
|
||||
The available features are client specific and may differ.
|
||||
Clients dedicated to Friendica are marked in **bold**.
|
||||
|
||||
#### Android
|
||||
|
||||
* [AndStatus](http://andstatus.org) ([F-Droid](https://f-droid.org/repository/browse/?fdid=org.andstatus.app), [Google Play](https://play.google.com/store/apps/details?id=org.andstatus.app))
|
||||
* [Fedilab](https://fedilab.app) ([F-Droid](https://f-droid.org/app/fr.gouv.etalab.mastodon), [Google Play](https://play.google.com/store/apps/details?id=app.fedilab.android))
|
||||
* [Friendiqa](https://git.friendi.ca/lubuwest/Friendiqa) ([F-Droid](https://git.friendi.ca/lubuwest/Friendiqa#install), [Google Play](https://play.google.com/store/apps/details?id=org.qtproject.friendiqa))
|
||||
* **[Friendiqa](https://git.friendi.ca/lubuwest/Friendiqa)** ([F-Droid](https://git.friendi.ca/lubuwest/Friendiqa#install), [Google Play](https://play.google.com/store/apps/details?id=org.qtproject.friendiqa))
|
||||
* [Husky](https://codeberg.org/husky/husky) ([F-Droid](https://f-droid.org/repository/browse/?fdid=su.xash.husky), [Google Play](https://play.google.com/store/apps/details?id=su.xash.husky))
|
||||
* [Mastodon](https://github.com/mastodon/mastodon-android) ([F-Droid](https://f-droid.org/en/packages/org.joinmastodon.android/), [Google Play](https://play.google.com/store/apps/details?id=org.joinmastodon.android))
|
||||
* [Pachli](https://pachli.app/) ([F-Droid](https://f-droid.org/en/packages/app.pachli/), [Google Play](https://play.google.com/store/apps/details?id=app.pachli))
|
||||
* **[Raccoon for Friendica](https://github.com/LiveFastEatTrashRaccoon/RaccoonForFriendica)** ([F-Droid](https://f-droid.org/packages/com.livefast.eattrash.raccoonforfriendica), [Google Play](https://play.google.com/apps/testing/com.livefast.eattrash.raccoonforfriendica))
|
||||
* **[Relatica](https://gitlab.com/mysocialportal/relatica)**
|
||||
* [Subway Tooter](https://github.com/tateisu/SubwayTooter) ([F-Droid via Izzy](https://android.izzysoft.de/repo/apk/jp.juggler.subwaytooter.noFcm))
|
||||
* [Tooot](https://tooot.app/) ([Google Play](https://play.google.com/store/apps/details?id=com.xmflsct.app.tooot))
|
||||
* [Tusky](https://tusky.app) ([F-Droid](https://f-droid.org/repository/browse/?fdid=com.keylesspalace.tusky), [Google Play](https://play.google.com/store/apps/details?id=com.keylesspalace.tusky))
|
||||
|
@ -195,6 +198,7 @@ The available features are client specific and may differ.
|
|||
#### iOS
|
||||
|
||||
* [Mastodon](https://joinmastodon.org/apps) ([App Store](https://apps.apple.com/us/app/mastodon-for-iphone/id1571998974))
|
||||
* **[Relatica](https://gitlab.com/mysocialportal/relatica)**
|
||||
* [Stella*](https://www.stella-app.net/) ([App Store](https://apps.apple.com/us/app/stella-for-mastodon-twitter/id921372048))
|
||||
* [Tooot](https://github.com/tooot-app) ([App Store](https://apps.apple.com/app/id1549772269))
|
||||
* [TwidereX](https://github.com/TwidereProject/TwidereX-iOS) ([App Store](https://apps.apple.com/app/twidere-x/id1530314034))
|
||||
|
@ -202,17 +206,20 @@ The available features are client specific and may differ.
|
|||
#### Linux
|
||||
|
||||
* [Choqok](https://choqok.kde.org)
|
||||
* [Whalebird](https://whalebird.social/en/desktop/contents) ([GitHub](https://github.com/h3poteto/whalebird-desktop))
|
||||
* **[Relatica](https://gitlab.com/mysocialportal/relatica)**
|
||||
* [TheDesk](https://thedesk.top/en/) ([GitHub](https://github.com/cutls/TheDesk))
|
||||
* [Toot](https://toot.readthedocs.io/en/latest/)
|
||||
* [Whalebird](https://whalebird.social/en/desktop/contents) ([GitHub](https://github.com/h3poteto/whalebird-desktop))
|
||||
|
||||
#### macOS
|
||||
|
||||
* **[Relatica](https://gitlab.com/mysocialportal/relatica)**
|
||||
* [TheDesk](https://thedesk.top/en/) ([GitHub](https://github.com/cutls/TheDesk))
|
||||
* [Whalebird](https://whalebird.social/en/desktop/contents) ([App Store](https://apps.apple.com/de/app/whalebird/id1378283354), [GitHub](https://github.com/h3poteto/whalebird-desktop))
|
||||
|
||||
#### Windows
|
||||
|
||||
* **[Relatica](https://gitlab.com/mysocialportal/relatica)**
|
||||
* [TheDesk](https://thedesk.top/en/) ([GitHub](https://github.com/cutls/TheDesk))
|
||||
* [Whalebird](https://whalebird.social/en/desktop/contents) ([Microsoft Store](https://apps.microsoft.com/detail/9nbw4csdv5hc), [GitHub](https://github.com/h3poteto/whalebird-desktop))
|
||||
|
||||
|
|
|
@ -76,14 +76,6 @@ This makes the software much easier to update.
|
|||
The Linux commands to clone the repository into a directory "mywebsite" would be
|
||||
|
||||
git clone https://github.com/friendica/friendica.git -b stable mywebsite
|
||||
cd mywebsite
|
||||
bin/composer.phar install --no-dev
|
||||
|
||||
Make sure the folder *view/smarty3* exists and is writable by the webserver user, in this case *www-data*
|
||||
|
||||
mkdir -p view/smarty3
|
||||
chown www-data:www-data view/smarty3
|
||||
chmod 775 view/smarty3
|
||||
|
||||
Get the addons by going into your website folder.
|
||||
|
||||
|
@ -93,10 +85,20 @@ Clone the addon repository (separately):
|
|||
|
||||
git clone https://github.com/friendica/friendica-addons.git -b stable addon
|
||||
|
||||
Install the dependencies:
|
||||
|
||||
bin/composer.phar run install:prod
|
||||
|
||||
Make sure the folder *view/smarty3* exists and is writable by the webserver user, in this case *www-data*
|
||||
|
||||
mkdir -p view/smarty3
|
||||
chown www-data:www-data view/smarty3
|
||||
chmod 775 view/smarty3
|
||||
|
||||
If you want to use the development version of Friendica you can switch to the develop branch in the repository by running
|
||||
|
||||
git checkout develop
|
||||
bin/composer.phar install
|
||||
bin/composer.phar run install:prod
|
||||
cd addon
|
||||
git checkout develop
|
||||
|
||||
|
@ -216,7 +218,6 @@ All options will be saved in the `config/local.config.php` and are overruling th
|
|||
- `-U|--dbuser <username>` The username of the mysql/mariadb database login (env `MYSQL_USER` or `MYSQL_USERNAME`)
|
||||
- `-P|--dbpass <password>` The password of the mysql/mariadb database login (env `MYSQL_PASSWORD`)
|
||||
- `-d|--dbdata <database>` The name of the mysql/mariadb database (env `MYSQL_DATABASE`)
|
||||
- `-u|--urlpath <url_path>` The URL path of Friendica - f.e. '/friendica' (env `FRIENDICA_URL_PATH`)
|
||||
- `-b|--phppath <php_path>` The path of the PHP binary (env `FRIENDICA_PHP_PATH`)
|
||||
- `-A|--admin <mail>` The admin email address of Friendica (env `FRIENDICA_ADMIN_MAIL`)
|
||||
- `-T|--tz <timezone>` The timezone of Friendica (env `FRIENDICA_TZ`)
|
||||
|
@ -268,7 +269,7 @@ You might wish to delete/rename `config/local.config.php` to another name and dr
|
|||
Set up a cron job or scheduled task to run the worker once every 5-10 minutes in order to perform background processing.
|
||||
Example:
|
||||
|
||||
cd /base/directory; /path/to/php bin/worker.php
|
||||
cd /base/directory; /path/to/php bin/console.php worker
|
||||
|
||||
Change "/base/directory", and "/path/to/php" as appropriate for your situation.
|
||||
|
||||
|
@ -277,7 +278,7 @@ Change "/base/directory", and "/path/to/php" as appropriate for your situation.
|
|||
If you are using a Linux server, run "crontab -e" and add a line like the
|
||||
one shown, substituting for your unique paths and settings:
|
||||
|
||||
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php bin/worker.php
|
||||
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php bin/console.php worker
|
||||
|
||||
You can generally find the location of PHP by executing "which php".
|
||||
If you run into trouble with this section please contact your hosting provider for assistance.
|
||||
|
@ -290,11 +291,11 @@ Once you have installed Friendica and created an admin account as part of the pr
|
|||
#### worker alternative: daemon
|
||||
Otherwise, you’ll need to use the command line on your remote server and start the Friendica daemon (background task) using the following command:
|
||||
|
||||
cd /path/to/friendica; php bin/daemon.php start
|
||||
cd /path/to/friendica; php bin/console.php daemon start
|
||||
|
||||
Once started, you can check the daemon status using the following command:
|
||||
|
||||
cd /path/to/friendica; php bin/daemon.php status
|
||||
cd /path/to/friendica; php bin/console.php daemon status
|
||||
|
||||
After a server restart or any other failure, the daemon needs to be restarted.
|
||||
This could be achieved by a cronjob.
|
||||
|
@ -426,7 +427,7 @@ provided by one of our members.
|
|||
>
|
||||
> */10 * * * * cd /var/www/friendica/friendica/ && sudo -u www-data /usr/bin/php \
|
||||
> -d suhosin.executor.func.blacklist=none \
|
||||
> -d suhosin.executor.eval.blacklist=none -f bin/worker.php
|
||||
> -d suhosin.executor.eval.blacklist=none -f bin/console.php
|
||||
>
|
||||
> This worked well for simple test cases, but the friendica-cron still failed
|
||||
> with a fatal error:
|
||||
|
@ -435,7 +436,7 @@ provided by one of our members.
|
|||
> (attacker 'REMOTE_ADDR not set', file '/var/www/friendica/friendica/boot.php',
|
||||
> line 1341)
|
||||
>
|
||||
> After a while I noticed, that `bin/worker.php` calls further PHP script via `proc_open`.
|
||||
> After a while I noticed, that `bin/console.php worker` calls further PHP script via `proc_open`.
|
||||
> These scripts themselves also use `proc_open` and fail, because they are NOT
|
||||
> called with `-d suhosin.executor.func.blacklist=none`.
|
||||
>
|
||||
|
|
|
@ -28,7 +28,7 @@ Jetstream is a service that connects to the Bluesky firehose.
|
|||
With Jetstream, messages arrive in real time rather than having to be polled.
|
||||
It also enables real-time processing of blocks or tracking activities performed by the user via the Bluesky website or application.
|
||||
|
||||
To enable Jetstream processing, run `bin/jetstream.php' from the command line.
|
||||
To enable Jetstream processing, run `bin/console.php jetstream' from the command line.
|
||||
You will need to define the process id file in local.config.php in the 'jetstream' section using the key 'pidfile'.
|
||||
|
||||
To keep track of the messages processed and the drift (the time difference between the date of the message and the date the system processed that message), some fields are added to the statistics endpoint.
|
|
@ -57,7 +57,7 @@ Finally, you may also want to optimise your database with the following command:
|
|||
|
||||
### Going offline
|
||||
Stop background tasks and put your server in maintenance mode.
|
||||
1. If you had set up a worker cron job like this ``*/10 * * * * cd /var/www/friendica; /usr/bin/php bin/worker.php`` run ``crontab -e`` and comment out this line. Alternatively if you deploy a worker daemon, disable this instead.
|
||||
1. If you had set up a worker cron job like this ``*/10 * * * * cd /var/www/friendica; /usr/bin/php bin/console.php worker`` run ``crontab -e`` and comment out this line. Alternatively if you deploy a worker daemon, disable this instead.
|
||||
2. Put your server into maintenance mode: ``bin/console maintenance 1 "We are currently upgrading our system and will be back soon."``
|
||||
|
||||
## Dumping DB
|
||||
|
@ -78,7 +78,7 @@ Ensure the newly created database credentials are identical to the setting in th
|
|||
### Cron job for worker
|
||||
Set up the required daily cron job.
|
||||
Run ``crontab -e`` and add the following line according to your system specification
|
||||
``*/10 * * * * cd /var/www/friendica; /usr/bin/php bin/worker.php``
|
||||
``*/10 * * * * cd /var/www/friendica; /usr/bin/php bin/console.php worker``
|
||||
|
||||
### DNS settings
|
||||
Adjust your DNS records by pointing them to your new server.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
This is your Suggested Friends page.
|
||||
If you get lost, you can <a href="help/Quick-Start-makenewfriends">click this link</a> to bring yourself back here.
|
||||
If you get lost, you can <a href="help/Quick-Start-makingnewfriends">click this link</a> to bring yourself back here.
|
||||
|
||||
This is a bit like the Friend Suggestions page of Facebook.
|
||||
Everybody on this list has agreed that they may be suggested as a friend.
|
||||
|
@ -16,6 +16,6 @@ Click the link at the top of this page to go back to the suggested friends list
|
|||
Feel uncomfortable adding people you don't know?
|
||||
Don't worry - that's where <a href="help/Quick-Start-groupsandpages">Groups and Pages</a> come in!
|
||||
|
||||
<iframe src="suggest" width="950" height="600"></iframe>
|
||||
<iframe src="contact/suggestions" width="950" height="600"></iframe>
|
||||
|
||||
|
||||
|
|
|
@ -419,7 +419,7 @@ We strongly discourage you from doing so, as this will break federation to other
|
|||
Say you have a subdirectory for tests and put Friendica into a further subdirectory, the config would be:
|
||||
|
||||
'system' => [
|
||||
'urlpath' => 'tests/friendica',
|
||||
'url' => 'https://example.com/tests/friendica',
|
||||
],
|
||||
|
||||
## Other exceptions
|
||||
|
|
|
@ -83,6 +83,8 @@ return [
|
|||
|
||||
## Addons
|
||||
|
||||
> ⚠️ Since Friendica 2025.02 the strategy hooks for addons are deprecated, please use PHP hooks instead.
|
||||
|
||||
The hook logic is useful for decoupling the Friendica core logic, but its primary goal is to modularize Friendica in creating addons.
|
||||
|
||||
Therefor you can either use the interfaces directly as shown above, or you can place your own `hooks.config.php` file inside a `static` directory directly under your addon core directory.
|
||||
|
|
|
@ -30,7 +30,7 @@ You can get the latest changes at any time with
|
|||
|
||||
cd path/to/friendica
|
||||
git pull
|
||||
bin/composer.phar install --no-dev
|
||||
bin/composer.phar run install:prod
|
||||
|
||||
The addon tree has to be updated separately like so:
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ What you need to do:
|
|||
Please use an up-to-date vagrant version from https://www.vagrantup.com/downloads.html.
|
||||
2. Git clone your Friendica repository.
|
||||
Inside, you'll find a `Vagrantfile` and some scripts in the `bin/dev` folder.
|
||||
Pull the PHP requirements with `bin/composer install`.
|
||||
Pull the PHP requirements with `bin/composer.phar install`.
|
||||
3. Run `vagrant up` from inside the friendica clone.
|
||||
This will start the virtual machine.
|
||||
Be patient: When it runs for the first time, it downloads a Debian Server image and installs Friendica.
|
||||
|
|
|
@ -46,9 +46,9 @@ The code will be something like:
|
|||
// mod/network.php
|
||||
<?php
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\AppHelper;
|
||||
|
||||
function network_content(App $a) {
|
||||
function network_content(AppHelper $appHelper) {
|
||||
$itemsmanager = new \Friendica\ItemsManager();
|
||||
$items = $itemsmanager->getAll();
|
||||
|
||||
|
|
|
@ -41,16 +41,24 @@ Fields
|
|||
| blocked | Server is blocked | boolean | YES | | NULL | |
|
||||
| failed | Connection failed | boolean | YES | | NULL | |
|
||||
| next_contact | Next connection request | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
| redirect-gsid | Target Gserver id in case of a redirect | int unsigned | YES | | NULL | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
||||
| Name | Fields |
|
||||
| ------------ | ----------------- |
|
||||
| ------------- | ----------------- |
|
||||
| PRIMARY | id |
|
||||
| nurl | UNIQUE, nurl(190) |
|
||||
| next_contact | next_contact |
|
||||
| network | network |
|
||||
| redirect-gsid | redirect-gsid |
|
||||
|
||||
Foreign Keys
|
||||
------------
|
||||
|
||||
| Field | Target Table | Target Field |
|
||||
|-------|--------------|--------------|
|
||||
| redirect-gsid | [gserver](help/database/db_gserver) | id |
|
||||
|
||||
Return to [database documentation](help/database)
|
||||
|
|
|
@ -30,6 +30,9 @@ Fields
|
|||
| publisher-url | URL of the publisher of the media | varbinary(383) | YES | | NULL | |
|
||||
| publisher-name | Name of the publisher of the media | varchar(255) | YES | | NULL | |
|
||||
| publisher-image | Image of the publisher of the media | varbinary(383) | YES | | NULL | |
|
||||
| language | Language information about this media in the ISO 639 format | char(3) | YES | | NULL | |
|
||||
| published | Publification date of this media | datetime | YES | | NULL | |
|
||||
| modified | Modification date of this media | datetime | YES | | NULL | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
|
|
@ -45,10 +45,10 @@ Indexes
|
|||
------------
|
||||
|
||||
| Name | Fields |
|
||||
| -------------------- | ----------------------- |
|
||||
| --------------------- | ----------------------- |
|
||||
| PRIMARY | id |
|
||||
| uid_uri-id | UNIQUE, uid, uri-id |
|
||||
| uri-id | uri-id |
|
||||
| uri-id_origin_deleted | uri-id, origin, deleted |
|
||||
| parent-uri-id | parent-uri-id |
|
||||
| thr-parent-id | thr-parent-id |
|
||||
| external-id | external-id |
|
||||
|
|
|
@ -362,7 +362,7 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
|
|||
|
||||
### src/Content/ContactBlock.php
|
||||
|
||||
Hook::callAll('contact_block_end', $arr);
|
||||
Hook::callAll('contact_block_end', $text);
|
||||
|
||||
### src/Content/Text/BBCode.php
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ Der Linux-Code, mit dem man die Dateien direkt in ein Verzeichnis wie "meinewebs
|
|||
|
||||
git clone https://github.com/friendica/friendica.git -b stable mywebsite
|
||||
cd mywebsite
|
||||
bin/composer.phar install
|
||||
bin/composer.phar run install:prod
|
||||
|
||||
Stelle sicher, dass der Ordner *view/smarty3* existiert and von dem Webserver-Benutzer beschreibbar ist
|
||||
|
||||
|
@ -85,7 +85,7 @@ Wenn du die Entwickler Version von Friendica verwenden möchtest kannst du auf d
|
|||
Dies tust du mit den folgenden Befehlen
|
||||
|
||||
git checkout develop
|
||||
bin/composer.phar install
|
||||
bin/composer.phar run install:prod
|
||||
cd addon
|
||||
git checkout develop
|
||||
|
||||
|
@ -210,13 +210,13 @@ Gehe in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus:
|
|||
Erstelle einen Cron job oder einen regelmäßigen Task, um den Poller alle 5-10 Minuten im Hintergrund ablaufen zu lassen.
|
||||
Beispiel:
|
||||
|
||||
cd /base/directory; /path/to/php bin/worker.php
|
||||
cd /base/directory; /path/to/php bin/console.php worker
|
||||
|
||||
Ändere "/base/directory" und "/path/to/php" auf deine Systemvorgaben.
|
||||
|
||||
Wenn du einen Linux-Server nutzt, benutze den Befehl "crontab -e" und ergänze eine Zeile wie die Folgende; angepasst an dein System
|
||||
|
||||
`*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php bin/worker.php`
|
||||
`*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php bin/console.php worker`
|
||||
|
||||
Du kannst den PHP-Pfad finden, indem du den Befehl „which php“ ausführst.
|
||||
Wenn du Schwierigkeiten mit diesem Schritt hast, kannst du deinen Hosting-Anbieter kontaktieren.
|
||||
|
|
|
@ -27,7 +27,7 @@ Jetstream ist ein Dienst, der sich mit dem Bluesky-Firehose verbindet.
|
|||
Mit Jetstream kommen die Nachrichten in Echtzeit an und müssen nicht erst abgefragt werden.
|
||||
Es ermöglicht auch die Echtzeitverarbeitung von Blöcken oder Tracking-Aktivitäten, die über die Bluesky-Website oder -Anwendung durchgeführt werden.
|
||||
|
||||
Um die Jetstream-Verarbeitung zu aktivieren, führe `bin/jetstream.php' über die Befehlszeile aus.
|
||||
Um die Jetstream-Verarbeitung zu aktivieren, führe `bin/console.php daemon' über die Befehlszeile aus.
|
||||
Du musst vorher die Prozess-ID-Datei in local.config.php im Abschnitt „jetstream“ mit dem Schlüssel „pidfile“ definieren.
|
||||
|
||||
Um die verarbeiteten Nachrichten und die Drift (die Zeitdifferenz zwischen dem Datum der Nachricht und dem Datum, an dem das System diese Nachricht verarbeitet hat) zu verfolgen, wurden dem Statistik-Endpunkt einige Felder hinzugefügt.
|
||||
|
|
|
@ -4,7 +4,7 @@ Neue Freunde finden
|
|||
* [Zur Startseite der Hilfe](help)
|
||||
|
||||
Hier siehst Du die Kontaktvorschläge.
|
||||
Wenn Du Dich mal verirrt hast, kannst Du diesen Link klicken und wieder hierher kommen.
|
||||
Wenn Du Dich mal verirrt hast, kannst Du <a href="help/Quick-Start-makingnewfriends">diesen Link klicken</a> und wieder hierher kommen.
|
||||
|
||||
Diese Seite funktioniert in etwa wie die Seite für Kontaktvorschläge in Facebook.
|
||||
Jeder auf dieser Liste hat zugestimmt, als Kontaktvorschlag zu erscheinen.
|
||||
|
@ -23,6 +23,6 @@ Klicke einfach auf den Link oben auf dieser Seite und Du gelangst zur Seite mit
|
|||
Du willst nicht einfach Personen hinzufügen, die du nicht kennst?
|
||||
Kein Problem - an dieser Stelle kommen wir zu den <a href="help/Quick-Start-groupsandpages">Gruppen und Seiten</a>.
|
||||
|
||||
<iframe src="suggest" width="950" height="600"></iframe>
|
||||
<iframe src="contact/suggestions" width="950" height="600"></iframe>
|
||||
|
||||
|
||||
|
|
|
@ -410,7 +410,7 @@ Wir raten allerdings dringen davon ab, da es die Interoperabilität mit anderen
|
|||
Mal angenommen, du hast ein Unterverzeichnis tests und willst Friendica in ein weiteres Unterverzeichnis installieren, dann lautet die Konfiguration hierfür:
|
||||
|
||||
'system' => [
|
||||
'urlpath' => 'tests/friendica',
|
||||
'url' => 'https://example.com/tests/friendica',
|
||||
],
|
||||
|
||||
## Weitere Ausnahmen
|
||||
|
|
35
doc/stats.md
Normal file
35
doc/stats.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
Monitoring
|
||||
===========
|
||||
|
||||
* [Home](help)
|
||||
|
||||
## Endpoints
|
||||
|
||||
Currently, there are two endpoints for statistics available
|
||||
|
||||
- `/stats` Returns some basic statistics of the current node
|
||||
- `/stats/caching` Returns statistics of cache or lock instances, which are used for the currend node
|
||||
|
||||
### `/stats`
|
||||
|
||||
The statistics contain data about the worker performance, the last cron call, number of reports, inbound and outbound packets, posts and comments.
|
||||
|
||||
### `/stats/caching`
|
||||
|
||||
The statistics contain data about the opcache, the used caching (like memory usage, hits/misses, entries, ...) and the used lock (including the cache data)
|
||||
|
||||
## Configuration
|
||||
|
||||
Please define 'stats_key' in your local.config.php in the 'system' section to be able to access the statistics page at /stats?key=your-defined-stats_key
|
||||
|
||||
## 3rd Party monitoring tools
|
||||
|
||||
### Zabbix
|
||||
|
||||
To monitor the health status of your Friendica installation, you can use for example a tool like Zabbix.
|
||||
|
||||
### Prometheus
|
||||
|
||||
To use [prometheus](https://prometheus.io) for gathering metrics, use the [Friendica exporter](https://git.friendi.ca/friendica/friendica-exporter).
|
||||
|
||||
You can find the installation instructions here: https://git.friendi.ca/friendica/friendica-exporter#installation
|
12
doc/tools.md
12
doc/tools.md
|
@ -78,15 +78,3 @@ The following will compress */var/log/friendica* (assuming this is the location
|
|||
daily
|
||||
rotate 2
|
||||
}
|
||||
|
||||
### Zabbix
|
||||
|
||||
To monitor the health status of your Friendica installation, you can use for example a tool like Zabbix. Please define 'stats_key' in your local.config.php in the 'system' section to be able to access the statistics page at /stats?key=your-defined-stats_key
|
||||
|
||||
The statistics contain data about the worker performance, the last cron call, number of reports, inbound and outbound packets, posts and comments.
|
||||
|
||||
### Prometheus
|
||||
|
||||
To use [prometheus](https://prometheus.io) for gathering metrics, use the [Friendica exporter](https://git.friendi.ca/friendica/friendica-exporter).
|
||||
|
||||
You can find the installation instructions here: https://git.friendi.ca/friendica/friendica-exporter#installation
|
||||
|
|
30
index.php
30
index.php
|
@ -5,38 +5,18 @@
|
|||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use Dice\Dice;
|
||||
|
||||
$start_time = microtime(true);
|
||||
|
||||
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||
die('Vendor path not found. Please execute "bin/composer.phar --no-dev install" on the command line in the web root.');
|
||||
die('Vendor path not found. Please execute "bin/composer.phar run install:prod" on the command line in the web root.');
|
||||
}
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
$dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php');
|
||||
/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */
|
||||
$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class);
|
||||
$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies'));
|
||||
$dice = $dice->addRule(Friendica\App\Mode::class, ['call' => [['determineRunMode', [false, $_SERVER], Dice::CHAIN_CALL]]]);
|
||||
$request = \GuzzleHttp\Psr7\ServerRequest::fromGlobals();
|
||||
|
||||
\Friendica\DI::init($dice);
|
||||
$container = \Friendica\Core\DiceContainer::fromBasePath(__DIR__);
|
||||
|
||||
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
|
||||
$app = \Friendica\App::fromContainer($container);
|
||||
|
||||
$a = \Friendica\DI::app();
|
||||
|
||||
\Friendica\DI::mode()->setExecutor(\Friendica\App\Mode::INDEX);
|
||||
|
||||
$a->runFrontend(
|
||||
$dice->create(\Friendica\App\Router::class),
|
||||
$dice->create(\Friendica\Core\PConfig\Capability\IManagePersonalConfigValues::class),
|
||||
$dice->create(\Friendica\Security\Authentication::class),
|
||||
$dice->create(\Friendica\App\Page::class),
|
||||
$dice->create(\Friendica\Content\Nav::class),
|
||||
$dice->create(Friendica\Module\Special\HTTPException::class),
|
||||
new \Friendica\Util\HTTPInputData($_SERVER),
|
||||
$start_time,
|
||||
$_SERVER
|
||||
);
|
||||
$app->processRequest($request, $start_time);
|
||||
|
|
40
mod/item.php
40
mod/item.php
|
@ -16,16 +16,14 @@
|
|||
* information.
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Conversation;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Event\ArrayFilterEvent;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\ItemURI;
|
||||
|
@ -45,7 +43,11 @@ function item_post()
|
|||
item_drop($uid, $_REQUEST['dropitems']);
|
||||
}
|
||||
|
||||
Hook::callAll('post_local_start', $_REQUEST);
|
||||
$eventDispatcher = DI::eventDispatcher();
|
||||
|
||||
$_REQUEST = $eventDispatcher->dispatch(
|
||||
new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL_START, $_REQUEST)
|
||||
)->getArray();
|
||||
|
||||
$return_path = $_REQUEST['return'] ?? '';
|
||||
$preview = intval($_REQUEST['preview'] ?? 0);
|
||||
|
@ -57,7 +59,7 @@ function item_post()
|
|||
*/
|
||||
if (!$preview && !empty($_REQUEST['post_id_random'])) {
|
||||
if (DI::session()->get('post-random') == $_REQUEST['post_id_random']) {
|
||||
Logger::warning('duplicate post');
|
||||
DI::logger()->warning('duplicate post');
|
||||
item_post_return(DI::baseUrl(), $return_path);
|
||||
} else {
|
||||
DI::session()->set('post-random', $_REQUEST['post_id_random']);
|
||||
|
@ -166,7 +168,7 @@ function item_insert(int $uid, array $request, bool $preview, string $return_pat
|
|||
// This enables interaction like starring and saving into folders
|
||||
if ($toplevel_item['uid'] == 0) {
|
||||
$stored = Item::storeForUserByUriId($toplevel_item['uri-id'], $post['uid'], ['post-reason' => Item::PR_ACTIVITY]);
|
||||
Logger::info('Public item stored for user', ['uri-id' => $toplevel_item['uri-id'], 'uid' => $post['uid'], 'stored' => $stored]);
|
||||
DI::logger()->info('Public item stored for user', ['uri-id' => $toplevel_item['uri-id'], 'uid' => $post['uid'], 'stored' => $stored]);
|
||||
}
|
||||
|
||||
$post['parent'] = $toplevel_item['id'];
|
||||
|
@ -198,7 +200,7 @@ function item_insert(int $uid, array $request, bool $preview, string $return_pat
|
|||
|
||||
$post = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]);
|
||||
if (!$post) {
|
||||
Logger::error('Item couldn\'t be fetched.', ['post_id' => $post_id]);
|
||||
DI::logger()->error('Item couldn\'t be fetched.', ['post_id' => $post_id]);
|
||||
if ($return_path) {
|
||||
DI::baseUrl()->redirect($return_path);
|
||||
}
|
||||
|
@ -214,7 +216,7 @@ function item_insert(int $uid, array $request, bool $preview, string $return_pat
|
|||
DI::contentItem()->copyPermissions($post['thr-parent-id'], $post['uri-id'], $post['parent-uri-id']);
|
||||
}
|
||||
|
||||
Logger::debug('post_complete');
|
||||
DI::logger()->debug('post_complete');
|
||||
|
||||
item_post_return(DI::baseUrl(), $return_path);
|
||||
// NOTREACHED
|
||||
|
@ -277,14 +279,24 @@ function item_process(array $post, array $request, bool $preview, string $return
|
|||
System::jsonExit(['preview' => $o]);
|
||||
}
|
||||
|
||||
Hook::callAll('post_local', $post);
|
||||
$eventDispatcher = DI::eventDispatcher();
|
||||
|
||||
$hook_data = [
|
||||
'item' => $post,
|
||||
];
|
||||
|
||||
$hook_data = $eventDispatcher->dispatch(
|
||||
new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL, $hook_data)
|
||||
)->getArray();
|
||||
|
||||
$post = $hook_data['item'] ?? $post;
|
||||
|
||||
unset($post['edit']);
|
||||
unset($post['self']);
|
||||
unset($post['api_source']);
|
||||
|
||||
if (!empty($request['scheduled_at'])) {
|
||||
$scheduled_at = DateTimeFormat::convert($request['scheduled_at'], 'UTC', DI::app()->getTimeZone());
|
||||
$scheduled_at = DateTimeFormat::convert($request['scheduled_at'], 'UTC', DI::appHelper()->getTimeZone());
|
||||
if ($scheduled_at > DateTimeFormat::utcNow()) {
|
||||
unset($post['created']);
|
||||
unset($post['edited']);
|
||||
|
@ -298,7 +310,7 @@ function item_process(array $post, array $request, bool $preview, string $return
|
|||
}
|
||||
|
||||
if (!empty($post['cancel'])) {
|
||||
Logger::info('mod_item: post cancelled by addon.');
|
||||
DI::logger()->info('mod_item: post cancelled by addon.');
|
||||
if ($return_path) {
|
||||
DI::baseUrl()->redirect($return_path);
|
||||
}
|
||||
|
@ -325,12 +337,12 @@ function item_post_return($baseurl, $return_path)
|
|||
$json['reload'] = $baseurl . '/' . $_REQUEST['jsreload'];
|
||||
}
|
||||
|
||||
Logger::debug('post_json', ['json' => $json]);
|
||||
DI::logger()->debug('post_json', ['json' => $json]);
|
||||
|
||||
System::jsonExit($json);
|
||||
}
|
||||
|
||||
function item_content(App $a)
|
||||
function item_content()
|
||||
{
|
||||
if (!DI::userSession()->isAuthenticated()) {
|
||||
throw new HTTPException\UnauthorizedException();
|
||||
|
@ -445,7 +457,7 @@ function drop_item(int $id, string $return = ''): string
|
|||
item_redirect_after_action($item, $return);
|
||||
//NOTREACHED
|
||||
} else {
|
||||
Logger::warning('Permission denied.', ['local' => DI::userSession()->getLocalUserId(), 'uid' => $item['uid'], 'cid' => $contact_id]);
|
||||
DI::logger()->warning('Permission denied.', ['local' => DI::userSession()->getLocalUserId(), 'uid' => $item['uid'], 'cid' => $contact_id]);
|
||||
DI::sysmsg()->addNotice(DI::l10n()->t('Permission denied.'));
|
||||
DI::baseUrl()->redirect('display/' . $item['guid']);
|
||||
//NOTREACHED
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
|
@ -15,7 +14,7 @@ use Friendica\Model\User;
|
|||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
function lostpass_post(App $a)
|
||||
function lostpass_post()
|
||||
{
|
||||
$loginame = trim($_POST['login-name']);
|
||||
if (!$loginame) {
|
||||
|
@ -78,7 +77,7 @@ function lostpass_post(App $a)
|
|||
DI::baseUrl()->redirect();
|
||||
}
|
||||
|
||||
function lostpass_content(App $a)
|
||||
function lostpass_content()
|
||||
{
|
||||
if (DI::args()->getArgc() > 1) {
|
||||
$pwdreset_token = DI::args()->getArgv()[1];
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2010-2024, the Friendica project
|
||||
* SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
|
@ -207,7 +208,7 @@ function message_content()
|
|||
$r = get_messages(DI::userSession()->getLocalUserId(), $pager->getStart(), $pager->getItemsPerPage());
|
||||
|
||||
if (!DBA::isResult($r)) {
|
||||
DI::sysmsg()->addNotice(DI::l10n()->t('No messages.'));
|
||||
$o .= DI::l10n()->t('You have no messages.');
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
@ -222,7 +223,8 @@ function message_content()
|
|||
|
||||
$o .= $header;
|
||||
|
||||
$message = DBA::fetchFirst("
|
||||
$message = DBA::fetchFirst(
|
||||
"
|
||||
SELECT `mail`.*, `contact`.`name`, `contact`.`url`, `contact`.`thumb`
|
||||
FROM `mail`
|
||||
LEFT JOIN `contact` ON `mail`.`contact-id` = `contact`.`id`
|
||||
|
@ -245,7 +247,8 @@ function message_content()
|
|||
} else {
|
||||
$sql_extra = "AND `mail`.`parent-uri` = ?";
|
||||
}
|
||||
$messages_stmt = DBA::p("
|
||||
$messages_stmt = DBA::p(
|
||||
"
|
||||
SELECT `mail`.*, `contact`.`name`, `contact`.`url`, `contact`.`thumb`
|
||||
FROM `mail`
|
||||
LEFT JOIN `contact` ON `mail`.`contact-id` = `contact`.`id`
|
||||
|
@ -396,8 +399,7 @@ function get_messages(int $uid, int $start, int $limit): array
|
|||
LEFT JOIN `contact` c ON m.`contact-id` = c.`id`
|
||||
WHERE m.`uid` = ?
|
||||
ORDER BY m2.`mailcreated` DESC
|
||||
LIMIT ?, ?'
|
||||
, $uid, $uid, $start, $limit));
|
||||
LIMIT ?, ?', $uid, $uid, $start, $limit));
|
||||
}
|
||||
|
||||
function render_messages(array $msg, string $t): string
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Conversation;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Content\Pager;
|
||||
|
@ -17,7 +16,7 @@ use Friendica\Model\Item;
|
|||
use Friendica\Model\Post;
|
||||
use Friendica\Module\BaseProfile;
|
||||
|
||||
function notes_init(App $a)
|
||||
function notes_init()
|
||||
{
|
||||
if (! DI::userSession()->getLocalUserId()) {
|
||||
return;
|
||||
|
@ -27,8 +26,10 @@ function notes_init(App $a)
|
|||
}
|
||||
|
||||
|
||||
function notes_content(App $a, bool $update = false)
|
||||
function notes_content(bool $update = false)
|
||||
{
|
||||
$contactId = DI::appHelper()->getContactId();
|
||||
|
||||
if (!DI::userSession()->getLocalUserId()) {
|
||||
DI::sysmsg()->addNotice(DI::l10n()->t('Permission denied.'));
|
||||
return;
|
||||
|
@ -46,11 +47,11 @@ function notes_content(App $a, bool $update = false)
|
|||
'acl_data' => '',
|
||||
];
|
||||
|
||||
$o .= DI::conversation()->statusEditor($x, $a->getContactId());
|
||||
$o .= DI::conversation()->statusEditor($x, $contactId);
|
||||
}
|
||||
|
||||
$condition = ['uid' => DI::userSession()->getLocalUserId(), 'post-type' => Item::PT_PERSONAL_NOTE, 'gravity' => Item::GRAVITY_PARENT,
|
||||
'contact-id'=> $a->getContactId()];
|
||||
'contact-id'=> $contactId];
|
||||
|
||||
if (DI::mode()->isMobile()) {
|
||||
$itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_mobile_network',
|
||||
|
|
|
@ -11,14 +11,12 @@ use Friendica\Content\Nav;
|
|||
use Friendica\Content\Pager;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Core\ACL;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\DBStructure;
|
||||
use Friendica\DI;
|
||||
use Friendica\Event\ArrayFilterEvent;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Photo;
|
||||
|
@ -28,9 +26,7 @@ use Friendica\Model\Tag;
|
|||
use Friendica\Model\User;
|
||||
use Friendica\Module\BaseProfile;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Protocol\ActivityNamespace;
|
||||
use Friendica\Security\Security;
|
||||
use Friendica\Util\Crypto;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
@ -49,7 +45,7 @@ function photos_init()
|
|||
Nav::setSelected('home');
|
||||
|
||||
if (DI::args()->getArgc() > 1) {
|
||||
$owner = Profile::load(DI::app(), DI::args()->getArgv()[1], false);
|
||||
$owner = Profile::load(DI::appHelper(), DI::args()->getArgv()[1], false);
|
||||
if (!isset($owner['account_removed']) || $owner['account_removed']) {
|
||||
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
|
||||
}
|
||||
|
@ -279,7 +275,7 @@ function photos_post()
|
|||
}
|
||||
|
||||
if (!empty($_POST['rotate']) && (intval($_POST['rotate']) == 1 || intval($_POST['rotate']) == 2)) {
|
||||
Logger::debug('rotate');
|
||||
DI::logger()->debug('rotate');
|
||||
|
||||
$photo = Photo::getPhotoForUser($page_owner_uid, $resource_id);
|
||||
|
||||
|
@ -651,7 +647,11 @@ function photos_content()
|
|||
'default_upload' => true
|
||||
];
|
||||
|
||||
Hook::callAll('photo_upload_form', $ret);
|
||||
$eventDispatcher = DI::eventDispatcher();
|
||||
|
||||
$eventDispatcher->dispatch(
|
||||
new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_FORM, $ret)
|
||||
);
|
||||
|
||||
$default_upload_box = Renderer::replaceMacros(Renderer::getMarkupTemplate('photos_default_uploader_box.tpl'), []);
|
||||
$default_upload_submit = Renderer::replaceMacros(Renderer::getMarkupTemplate('photos_default_uploader_submit.tpl'), [
|
||||
|
@ -1022,14 +1022,14 @@ function photos_content()
|
|||
}
|
||||
}
|
||||
$tags = ['title' => DI::l10n()->t('Tags: '), 'tags' => $tag_arr];
|
||||
if ($cmd === 'edit') {
|
||||
if ($cmd === 'edit' && !empty($tag_arr)) {
|
||||
$tags['removeanyurl'] = 'post/' . $link_item['id'] . '/tag/remove?return=' . urlencode(DI::args()->getCommand());
|
||||
$tags['removetitle'] = DI::l10n()->t('[Select tags to remove]');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$edit = Null;
|
||||
$edit = null;
|
||||
if ($cmd === 'edit' && $can_post) {
|
||||
$edit_tpl = Renderer::getMarkupTemplate('photo_edit.tpl');
|
||||
|
||||
|
@ -1070,6 +1070,7 @@ function photos_content()
|
|||
$cmnt_tpl = Renderer::getMarkupTemplate('comment_item.tpl');
|
||||
$tpl = Renderer::getMarkupTemplate('photo_item.tpl');
|
||||
$return_path = DI::args()->getCommand();
|
||||
$addonHelper = DI::addonHelper();
|
||||
|
||||
if (!DBA::isResult($items)) {
|
||||
if (($can_post || Security::canWriteToUserWall($owner_uid))) {
|
||||
|
@ -1078,7 +1079,7 @@ function photos_content()
|
|||
* This should be better if done by a hook
|
||||
*/
|
||||
$qcomment = null;
|
||||
if (Addon::isEnabled('qcomment')) {
|
||||
if ($addonHelper->isAddonEnabled('qcomment')) {
|
||||
$words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words');
|
||||
$qcomment = $words ? explode("\n", $words) : [];
|
||||
}
|
||||
|
@ -1134,7 +1135,7 @@ function photos_content()
|
|||
* This should be better if done by a hook
|
||||
*/
|
||||
$qcomment = null;
|
||||
if (Addon::isEnabled('qcomment')) {
|
||||
if ($addonHelper->isAddonEnabled('qcomment')) {
|
||||
$words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words');
|
||||
$qcomment = $words ? explode("\n", $words) : [];
|
||||
}
|
||||
|
@ -1214,7 +1215,7 @@ function photos_content()
|
|||
* This should be better if done by a hook
|
||||
*/
|
||||
$qcomment = null;
|
||||
if (Addon::isEnabled('qcomment')) {
|
||||
if ($addonHelper->isAddonEnabled('qcomment')) {
|
||||
$words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words');
|
||||
$qcomment = $words ? explode("\n", $words) : [];
|
||||
}
|
||||
|
|
|
@ -9,14 +9,13 @@
|
|||
*
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Contact;
|
||||
|
||||
function update_contact_content(App $a)
|
||||
function update_contact_content()
|
||||
{
|
||||
if (!empty(DI::args()->get(1)) && !empty($_GET['force'])) {
|
||||
$contact = DBA::selectFirst('account-user-view', ['pid', 'deleted'], ['id' => DI::args()->get(1)]);
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
* AJAX synchronisation of notes page
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\DI;
|
||||
|
||||
require_once 'mod/notes.php';
|
||||
|
||||
function update_notes_content(App $a)
|
||||
function update_notes_content()
|
||||
{
|
||||
$profile_uid = intval($_GET['p']);
|
||||
|
||||
|
@ -28,7 +26,7 @@ function update_notes_content(App $a)
|
|||
*
|
||||
*/
|
||||
|
||||
$text = notes_content($a, $profile_uid);
|
||||
$text = notes_content($profile_uid);
|
||||
|
||||
System::htmlUpdateExit($text);
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ Description=Friendica Worker
|
|||
User=http
|
||||
#Adapt the path in the following line to your system, use 'which php' to find php path,
|
||||
#provide the absolute path for worker.php
|
||||
ExecStart=/usr/bin/php /www/path/bin/worker.php &
|
||||
ExecStart=/usr/bin/php /www/path/bin/console.php worker &
|
||||
|
|
690
src/App.php
690
src/App.php
|
@ -7,34 +7,50 @@
|
|||
|
||||
namespace Friendica;
|
||||
|
||||
use Exception;
|
||||
use Dice\Dice;
|
||||
use Friendica\App\Arguments;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\App\Page;
|
||||
use Friendica\App\Request;
|
||||
use Friendica\App\Router;
|
||||
use Friendica\Capabilities\ICanCreateResponses;
|
||||
use Friendica\Capabilities\ICanHandleRequests;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Core\Addon\AddonHelper;
|
||||
use Friendica\Core\Addon\Capability\ICanLoadAddons;
|
||||
use Friendica\Core\Config\Factory\Config;
|
||||
use Friendica\Core\Container;
|
||||
use Friendica\Core\Hooks\HookEventBridge;
|
||||
use Friendica\Core\Logger\LoggerManager;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\DiceContainer;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Logger\Capability\LogChannel;
|
||||
use Friendica\Core\Logger\Handler\ErrorHandler;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Update;
|
||||
use Friendica\Database\Definition\DbaDefinition;
|
||||
use Friendica\Database\Definition\ViewDefinition;
|
||||
use Friendica\Event\ConfigLoadedEvent;
|
||||
use Friendica\Event\Event;
|
||||
use Friendica\Module\Maintenance;
|
||||
use Friendica\Security\Authentication;
|
||||
use Friendica\Core\Config\ValueObject\Cache;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Theme;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Module\Special\HTTPException as ModuleHTTPException;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Protocol\ATProtocol\DID;
|
||||
use Friendica\Security\Authentication;
|
||||
use Friendica\Security\ExAuth;
|
||||
use Friendica\Security\OpenWebAuth;
|
||||
use Friendica\Util\BasePath;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\HTTPInputData;
|
||||
use Friendica\Util\HTTPSignature;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Strings;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
|
@ -46,27 +62,29 @@ use Psr\Log\LoggerInterface;
|
|||
* and anything else that might need to be passed around
|
||||
* before we spit the page out.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class App
|
||||
{
|
||||
const PLATFORM = 'Friendica';
|
||||
const CODENAME = 'Interrupted Fern';
|
||||
const VERSION = '2024.12';
|
||||
|
||||
// Allow themes to control internal parameters
|
||||
// by changing App values in theme.php
|
||||
private $theme_info = [
|
||||
'videowidth' => 425,
|
||||
'videoheight' => 350,
|
||||
];
|
||||
|
||||
private $timezone = '';
|
||||
private $profile_owner = 0;
|
||||
private $contact_id = 0;
|
||||
private $queue = [];
|
||||
const VERSION = '2025.02-dev';
|
||||
|
||||
/**
|
||||
* @var App\Mode The Mode of the Application
|
||||
* @internal
|
||||
*/
|
||||
public static function fromContainer(Container $container): self
|
||||
{
|
||||
return new self($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Container
|
||||
*/
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* @var Mode The Mode of the Application
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
|
@ -75,11 +93,6 @@ class App
|
|||
*/
|
||||
private $baseURL;
|
||||
|
||||
/** @var string The name of the current theme */
|
||||
private $currentTheme;
|
||||
/** @var string The name of the current mobile theme */
|
||||
private $currentMobileTheme;
|
||||
|
||||
/** @var string */
|
||||
private $requestId;
|
||||
|
||||
|
@ -101,11 +114,6 @@ class App
|
|||
*/
|
||||
private $profiler;
|
||||
|
||||
/**
|
||||
* @var Database The Friendica database connection
|
||||
*/
|
||||
private $database;
|
||||
|
||||
/**
|
||||
* @var L10n The translator
|
||||
*/
|
||||
|
@ -116,190 +124,239 @@ class App
|
|||
*/
|
||||
private $args;
|
||||
|
||||
/**
|
||||
* @var IManagePersonalConfigValues
|
||||
*/
|
||||
private $pConfig;
|
||||
|
||||
/**
|
||||
* @var IHandleUserSessions
|
||||
*/
|
||||
private $session;
|
||||
|
||||
/**
|
||||
* Set the profile owner ID
|
||||
*
|
||||
* @param int $owner_id
|
||||
* @return void
|
||||
* @var AppHelper $appHelper
|
||||
*/
|
||||
public function setProfileOwner(int $owner_id)
|
||||
private $appHelper;
|
||||
|
||||
private function __construct(Container $container)
|
||||
{
|
||||
$this->profile_owner = $owner_id;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the profile owner ID
|
||||
*
|
||||
* @return int
|
||||
* @internal
|
||||
*/
|
||||
public function getProfileOwner(): int
|
||||
public function processRequest(ServerRequestInterface $request, float $start_time): void
|
||||
{
|
||||
return $this->profile_owner;
|
||||
$this->container->addRule(Mode::class, [
|
||||
'call' => [
|
||||
['determineRunMode', [false, $request->getServerParams()], Dice::CHAIN_CALL],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->setupContainerForAddons();
|
||||
|
||||
$this->setupLogChannel(LogChannel::APP);
|
||||
|
||||
$this->setupLegacyServiceLocator();
|
||||
|
||||
$this->registerErrorHandler();
|
||||
|
||||
$this->registerEventDispatcher();
|
||||
|
||||
$this->requestId = $this->container->create(Request::class)->getRequestId();
|
||||
$this->auth = $this->container->create(Authentication::class);
|
||||
$this->config = $this->container->create(IManageConfigValues::class);
|
||||
$this->mode = $this->container->create(Mode::class);
|
||||
$this->baseURL = $this->container->create(BaseURL::class);
|
||||
$this->logger = $this->container->create(LoggerInterface::class);
|
||||
$this->profiler = $this->container->create(Profiler::class);
|
||||
$this->l10n = $this->container->create(L10n::class);
|
||||
$this->args = $this->container->create(Arguments::class);
|
||||
$this->session = $this->container->create(IHandleUserSessions::class);
|
||||
$this->appHelper = $this->container->create(AppHelper::class);
|
||||
|
||||
$addonHelper = $this->container->create(AddonHelper::class);
|
||||
|
||||
$this->load(
|
||||
$request->getServerParams(),
|
||||
$this->container->create(DbaDefinition::class),
|
||||
$this->container->create(ViewDefinition::class),
|
||||
$this->mode,
|
||||
$this->config,
|
||||
$this->profiler,
|
||||
$this->container->create(EventDispatcherInterface::class),
|
||||
$this->appHelper,
|
||||
$addonHelper,
|
||||
);
|
||||
|
||||
$this->registerTemplateEngine();
|
||||
|
||||
$this->runFrontend(
|
||||
$this->container->create(EventDispatcherInterface::class),
|
||||
$this->container->create(IManagePersonalConfigValues::class),
|
||||
$this->container->create(Page::class),
|
||||
$this->container->create(Nav::class),
|
||||
$addonHelper,
|
||||
$this->container->create(ModuleHTTPException::class),
|
||||
$start_time,
|
||||
$request
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the contact ID
|
||||
*
|
||||
* @param int $contact_id
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public function setContactId(int $contact_id)
|
||||
public function processConsole(array $serverParams): void
|
||||
{
|
||||
$this->contact_id = $contact_id;
|
||||
$argv = $serverParams['argv'] ?? [];
|
||||
|
||||
$this->setupContainerForAddons();
|
||||
|
||||
$this->setupLogChannel($this->determineLogChannel($argv));
|
||||
|
||||
$this->setupLegacyServiceLocator();
|
||||
|
||||
$this->registerErrorHandler();
|
||||
|
||||
$this->registerEventDispatcher();
|
||||
|
||||
$this->load(
|
||||
$serverParams,
|
||||
$this->container->create(DbaDefinition::class),
|
||||
$this->container->create(ViewDefinition::class),
|
||||
$this->container->create(Mode::class),
|
||||
$this->container->create(IManageConfigValues::class),
|
||||
$this->container->create(Profiler::class),
|
||||
$this->container->create(EventDispatcherInterface::class),
|
||||
$this->container->create(AppHelper::class),
|
||||
$this->container->create(AddonHelper::class),
|
||||
);
|
||||
|
||||
$this->registerTemplateEngine();
|
||||
|
||||
(\Friendica\Core\Console::create($this->container, $argv))->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contact ID
|
||||
*
|
||||
* @return int
|
||||
* @internal
|
||||
*/
|
||||
public function getContactId(): int
|
||||
public function processEjabberd(array $serverParams): void
|
||||
{
|
||||
return $this->contact_id;
|
||||
$this->setupContainerForAddons();
|
||||
|
||||
$this->setupLogChannel(LogChannel::AUTH_JABBERED);
|
||||
|
||||
$this->setupLegacyServiceLocator();
|
||||
|
||||
$this->registerErrorHandler();
|
||||
|
||||
$this->registerEventDispatcher();
|
||||
|
||||
$this->load(
|
||||
$serverParams,
|
||||
$this->container->create(DbaDefinition::class),
|
||||
$this->container->create(ViewDefinition::class),
|
||||
$this->container->create(Mode::class),
|
||||
$this->container->create(IManageConfigValues::class),
|
||||
$this->container->create(Profiler::class),
|
||||
$this->container->create(EventDispatcherInterface::class),
|
||||
$this->container->create(AppHelper::class),
|
||||
$this->container->create(AddonHelper::class),
|
||||
);
|
||||
|
||||
/** @var BasePath */
|
||||
$basePath = $this->container->create(BasePath::class);
|
||||
|
||||
// Check the database structure and possibly fixes it
|
||||
Update::check($basePath->getPath(), true);
|
||||
|
||||
$appMode = $this->container->create(Mode::class);
|
||||
|
||||
if ($appMode->isNormal()) {
|
||||
/** @var ExAuth $oAuth */
|
||||
$oAuth = $this->container->create(ExAuth::class);
|
||||
$oAuth->readStdin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timezone
|
||||
*
|
||||
* @param string $timezone A valid time zone identifier, see https://www.php.net/manual/en/timezones.php
|
||||
* @return void
|
||||
*/
|
||||
public function setTimeZone(string $timezone)
|
||||
private function setupContainerForAddons(): void
|
||||
{
|
||||
$this->timezone = (new \DateTimeZone($timezone))->getName();
|
||||
DateTimeFormat::setLocalTimeZone($this->timezone);
|
||||
/** @var ICanLoadAddons $addonLoader */
|
||||
$addonLoader = $this->container->create(ICanLoadAddons::class);
|
||||
|
||||
foreach ($addonLoader->getActiveAddonConfig('dependencies') as $name => $rule) {
|
||||
$this->container->addRule($name, $rule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timezone
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTimeZone(): string
|
||||
private function determineLogChannel(array $argv): string
|
||||
{
|
||||
return $this->timezone;
|
||||
$command = strtolower($argv[1] ?? '');
|
||||
|
||||
if ($command === 'daemon' || $command === 'jetstream') {
|
||||
return LogChannel::DAEMON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set workerqueue information
|
||||
*
|
||||
* @param array $queue
|
||||
* @return void
|
||||
*/
|
||||
public function setQueue(array $queue)
|
||||
{
|
||||
$this->queue = $queue;
|
||||
if ($command === 'worker') {
|
||||
return LogChannel::WORKER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch workerqueue information
|
||||
*
|
||||
* @return array Worker queue
|
||||
*/
|
||||
public function getQueue(): array
|
||||
{
|
||||
return $this->queue ?? [];
|
||||
// @TODO Add support for jetstream
|
||||
|
||||
return LogChannel::CONSOLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific workerqueue field
|
||||
*
|
||||
* @param string $index Work queue record to fetch
|
||||
* @return mixed Work queue item or NULL if not found
|
||||
*/
|
||||
public function getQueueValue(string $index)
|
||||
private function setupLogChannel(string $logChannel): void
|
||||
{
|
||||
return $this->queue[$index] ?? null;
|
||||
/** @var LoggerManager */
|
||||
$loggerManager = $this->container->create(LoggerManager::class);
|
||||
$loggerManager->changeLogChannel($logChannel);
|
||||
}
|
||||
|
||||
public function setThemeInfoValue(string $index, $value)
|
||||
private function setupLegacyServiceLocator(): void
|
||||
{
|
||||
$this->theme_info[$index] = $value;
|
||||
if ($this->container instanceof DiceContainer) {
|
||||
DI::init($this->container->getDice());
|
||||
}
|
||||
}
|
||||
|
||||
public function getThemeInfo()
|
||||
private function registerErrorHandler(): void
|
||||
{
|
||||
return $this->theme_info;
|
||||
ErrorHandler::register($this->container->create(LoggerInterface::class));
|
||||
}
|
||||
|
||||
public function getThemeInfoValue(string $index, $default = null)
|
||||
private function registerEventDispatcher(): void
|
||||
{
|
||||
return $this->theme_info[$index] ?? $default;
|
||||
/** @var \Friendica\Event\EventDispatcher */
|
||||
$eventDispatcher = $this->container->create(EventDispatcherInterface::class);
|
||||
|
||||
foreach (HookEventBridge::getStaticSubscribedEvents() as $eventName => $methodName) {
|
||||
$eventDispatcher->addListener($eventName, [HookEventBridge::class, $methodName]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current config cache of this node
|
||||
*
|
||||
* @return Cache
|
||||
*/
|
||||
public function getConfigCache()
|
||||
private function registerTemplateEngine(): void
|
||||
{
|
||||
return $this->config->getCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* The basepath of this app
|
||||
*
|
||||
* @return string Base path from configuration
|
||||
*/
|
||||
public function getBasePath(): string
|
||||
{
|
||||
return $this->config->get('system', 'basepath');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Database $database The Friendica Database
|
||||
* @param IManageConfigValues $config The Configuration
|
||||
* @param App\Mode $mode The mode of this Friendica app
|
||||
* @param BaseURL $baseURL The full base URL of this Friendica app
|
||||
* @param LoggerInterface $logger The current app logger
|
||||
* @param Profiler $profiler The profiler of this application
|
||||
* @param L10n $l10n The translator instance
|
||||
* @param App\Arguments $args The Friendica Arguments of the call
|
||||
* @param IManagePersonalConfigValues $pConfig Personal configuration
|
||||
* @param IHandleUserSessions $session The (User)Session handler
|
||||
* @param DbaDefinition $dbaDefinition
|
||||
* @param ViewDefinition $viewDefinition
|
||||
*/
|
||||
public function __construct(Request $request, Authentication $auth, Database $database, IManageConfigValues $config, App\Mode $mode, BaseURL $baseURL, LoggerInterface $logger, Profiler $profiler, L10n $l10n, Arguments $args, IManagePersonalConfigValues $pConfig, IHandleUserSessions $session, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition)
|
||||
{
|
||||
$this->requestId = $request->getRequestId();
|
||||
$this->auth = $auth;
|
||||
$this->database = $database;
|
||||
$this->config = $config;
|
||||
$this->mode = $mode;
|
||||
$this->baseURL = $baseURL;
|
||||
$this->profiler = $profiler;
|
||||
$this->logger = $logger;
|
||||
$this->l10n = $l10n;
|
||||
$this->args = $args;
|
||||
$this->pConfig = $pConfig;
|
||||
$this->session = $session;
|
||||
|
||||
$this->load($dbaDefinition, $viewDefinition);
|
||||
Renderer::registerTemplateEngine('Friendica\Render\FriendicaSmartyEngine');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the whole app instance
|
||||
*/
|
||||
protected function load(DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition)
|
||||
{
|
||||
if ($this->config->get('system', 'ini_max_execution_time') !== false) {
|
||||
set_time_limit((int)$this->config->get('system', 'ini_max_execution_time'));
|
||||
private function load(
|
||||
array $serverParams,
|
||||
DbaDefinition $dbaDefinition,
|
||||
ViewDefinition $viewDefinition,
|
||||
Mode $mode,
|
||||
IManageConfigValues $config,
|
||||
Profiler $profiler,
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
AppHelper $appHelper,
|
||||
AddonHelper $addonHelper
|
||||
): void {
|
||||
if ($config->get('system', 'ini_max_execution_time') !== false) {
|
||||
set_time_limit((int) $config->get('system', 'ini_max_execution_time'));
|
||||
}
|
||||
|
||||
if ($this->config->get('system', 'ini_pcre_backtrack_limit') !== false) {
|
||||
ini_set('pcre.backtrack_limit', (int)$this->config->get('system', 'ini_pcre_backtrack_limit'));
|
||||
if ($config->get('system', 'ini_pcre_backtrack_limit') !== false) {
|
||||
ini_set('pcre.backtrack_limit', (int) $config->get('system', 'ini_pcre_backtrack_limit'));
|
||||
}
|
||||
|
||||
// Normally this constant is defined - but not if "pcntl" isn't installed
|
||||
|
@ -310,27 +367,20 @@ class App
|
|||
// Ensure that all "strtotime" operations do run timezone independent
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
set_include_path(
|
||||
get_include_path() . PATH_SEPARATOR
|
||||
. $this->getBasePath() . DIRECTORY_SEPARATOR . 'include' . PATH_SEPARATOR
|
||||
. $this->getBasePath() . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR
|
||||
. $this->getBasePath());
|
||||
$profiler->reset();
|
||||
|
||||
$this->profiler->reset();
|
||||
|
||||
if ($this->mode->has(App\Mode::DBAVAILABLE)) {
|
||||
if ($mode->has(Mode::DBAVAILABLE)) {
|
||||
Core\Hook::loadHooks();
|
||||
$loader = (new Config())->createConfigFileManager($this->getBasePath(), $_SERVER);
|
||||
Core\Hook::callAll('load_config', $loader);
|
||||
$loader = (new Config())->createConfigFileManager($appHelper->getBasePath(), $addonHelper->getAddonPath(), $serverParams);
|
||||
|
||||
$eventDispatcher->dispatch(new ConfigLoadedEvent(ConfigLoadedEvent::CONFIG_LOADED, $loader));
|
||||
|
||||
// Hooks are now working, reload the whole definitions with hook enabled
|
||||
$dbaDefinition->load(true);
|
||||
$viewDefinition->load(true);
|
||||
}
|
||||
|
||||
$this->loadDefaultTimezone();
|
||||
// Register template engines
|
||||
Core\Renderer::registerTemplateEngine('Friendica\Render\FriendicaSmartyEngine');
|
||||
$this->loadDefaultTimezone($config, $appHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,166 +390,16 @@ class App
|
|||
*
|
||||
* @global string $default_timezone
|
||||
*/
|
||||
private function loadDefaultTimezone()
|
||||
private function loadDefaultTimezone(IManageConfigValues $config, AppHelper $appHelper)
|
||||
{
|
||||
if ($this->config->get('system', 'default_timezone')) {
|
||||
$timezone = $this->config->get('system', 'default_timezone', 'UTC');
|
||||
if ($config->get('system', 'default_timezone')) {
|
||||
$timezone = $config->get('system', 'default_timezone', 'UTC');
|
||||
} else {
|
||||
global $default_timezone;
|
||||
$timezone = $default_timezone ?? '' ?: 'UTC';
|
||||
}
|
||||
|
||||
$this->setTimeZone($timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current theme name. May be overridden by the mobile theme name.
|
||||
*
|
||||
* @return string Current theme name or empty string in installation phase
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentTheme(): string
|
||||
{
|
||||
if ($this->mode->isInstall()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Specific mobile theme override
|
||||
if (($this->mode->isMobile() || $this->mode->isTablet()) && $this->session->get('show-mobile', true)) {
|
||||
$user_mobile_theme = $this->getCurrentMobileTheme();
|
||||
|
||||
// --- means same mobile theme as desktop
|
||||
if (!empty($user_mobile_theme) && $user_mobile_theme !== '---') {
|
||||
return $user_mobile_theme;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->currentTheme) {
|
||||
$this->computeCurrentTheme();
|
||||
}
|
||||
|
||||
return $this->currentTheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current mobile theme name.
|
||||
*
|
||||
* @return string Mobile theme name or empty string if installer
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentMobileTheme(): string
|
||||
{
|
||||
if ($this->mode->isInstall()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (is_null($this->currentMobileTheme)) {
|
||||
$this->computeCurrentMobileTheme();
|
||||
}
|
||||
|
||||
return $this->currentMobileTheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for current theme name
|
||||
*
|
||||
* @param string $theme Name of current theme
|
||||
*/
|
||||
public function setCurrentTheme(string $theme)
|
||||
{
|
||||
$this->currentTheme = $theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for current mobile theme name
|
||||
*
|
||||
* @param string $theme Name of current mobile theme
|
||||
*/
|
||||
public function setCurrentMobileTheme(string $theme)
|
||||
{
|
||||
$this->currentMobileTheme = $theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the current theme name based on the node settings, the page owner settings and the user settings
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function computeCurrentTheme()
|
||||
{
|
||||
$system_theme = $this->config->get('system', 'theme');
|
||||
if (!$system_theme) {
|
||||
throw new Exception($this->l10n->t('No system theme config value set.'));
|
||||
}
|
||||
|
||||
// Sane default
|
||||
$this->setCurrentTheme($system_theme);
|
||||
|
||||
$page_theme = null;
|
||||
// Find the theme that belongs to the user whose stuff we are looking at
|
||||
if (!empty($this->profile_owner) && ($this->profile_owner != $this->session->getLocalUserId())) {
|
||||
// Allow folks to override user themes and always use their own on their own site.
|
||||
// This works only if the user is on the same server
|
||||
$user = $this->database->selectFirst('user', ['theme'], ['uid' => $this->profile_owner]);
|
||||
if ($this->database->isResult($user) && !$this->session->getLocalUserId()) {
|
||||
$page_theme = $user['theme'];
|
||||
}
|
||||
}
|
||||
|
||||
$theme_name = $page_theme ?: $this->session->get('theme', $system_theme);
|
||||
|
||||
$theme_name = Strings::sanitizeFilePathItem($theme_name);
|
||||
if ($theme_name
|
||||
&& in_array($theme_name, Theme::getAllowedList())
|
||||
&& (file_exists('view/theme/' . $theme_name . '/style.css')
|
||||
|| file_exists('view/theme/' . $theme_name . '/style.php'))
|
||||
) {
|
||||
$this->setCurrentTheme($theme_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the current mobile theme name based on the node settings, the page owner settings and the user settings
|
||||
*/
|
||||
private function computeCurrentMobileTheme()
|
||||
{
|
||||
$system_mobile_theme = $this->config->get('system', 'mobile-theme', '');
|
||||
|
||||
// Sane default
|
||||
$this->setCurrentMobileTheme($system_mobile_theme);
|
||||
|
||||
$page_mobile_theme = null;
|
||||
// Find the theme that belongs to the user whose stuff we are looking at
|
||||
if (!empty($this->profile_owner) && ($this->profile_owner != $this->session->getLocalUserId())) {
|
||||
// Allow folks to override user themes and always use their own on their own site.
|
||||
// This works only if the user is on the same server
|
||||
if (!$this->session->getLocalUserId()) {
|
||||
$page_mobile_theme = $this->pConfig->get($this->profile_owner, 'system', 'mobile-theme');
|
||||
}
|
||||
}
|
||||
|
||||
$mobile_theme_name = $page_mobile_theme ?: $this->session->get('mobile-theme', $system_mobile_theme);
|
||||
|
||||
$mobile_theme_name = Strings::sanitizeFilePathItem($mobile_theme_name);
|
||||
if ($mobile_theme_name == '---'
|
||||
||
|
||||
in_array($mobile_theme_name, Theme::getAllowedList())
|
||||
&& (file_exists('view/theme/' . $mobile_theme_name . '/style.css')
|
||||
|| file_exists('view/theme/' . $mobile_theme_name . '/style.php'))
|
||||
) {
|
||||
$this->setCurrentMobileTheme($mobile_theme_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a sane default if nothing is chosen or the specified theme does not exist.
|
||||
*
|
||||
* @return string Current theme's stylesheet path
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentThemeStylesheetPath(): string
|
||||
{
|
||||
return Core\Theme::getStylesheetPath($this->getCurrentTheme());
|
||||
$appHelper->setTimeZone($timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -510,23 +410,34 @@ class App
|
|||
*
|
||||
* This probably should change to limit the size of this monster method.
|
||||
*
|
||||
* @param App\Router $router
|
||||
* @param IManagePersonalConfigValues $pconfig
|
||||
* @param Authentication $auth The Authentication backend of the node
|
||||
* @param App\Page $page The Friendica page printing container
|
||||
* @param Page $page The Friendica page printing container
|
||||
* @param ModuleHTTPException $httpException The possible HTTP Exception container
|
||||
* @param HTTPInputData $httpInput A library for processing PHP input streams
|
||||
* @param float $start_time The start time of the overall script execution
|
||||
* @param array $server The $_SERVER array
|
||||
*
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, Nav $nav, ModuleHTTPException $httpException, HTTPInputData $httpInput, float $start_time, array $server)
|
||||
{
|
||||
$requeststring = ($server['REQUEST_METHOD'] ?? '') . ' ' . ($server['REQUEST_URI'] ?? '') . ' ' . ($server['SERVER_PROTOCOL'] ?? '');
|
||||
$this->logger->debug('Request received', ['address' => $server['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $server['HTTP_REFERER'] ?? '', 'user-agent' => $server['HTTP_USER_AGENT'] ?? '']);
|
||||
private function runFrontend(
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
IManagePersonalConfigValues $pconfig,
|
||||
Page $page,
|
||||
Nav $nav,
|
||||
AddonHelper $addonHelper,
|
||||
ModuleHTTPException $httpException,
|
||||
float $start_time,
|
||||
ServerRequestInterface $request
|
||||
) {
|
||||
$this->mode->setExecutor(Mode::INDEX);
|
||||
|
||||
$httpInput = new HTTPInputData($request->getServerParams());
|
||||
$serverVars = $request->getServerParams();
|
||||
$queryVars = $request->getQueryParams();
|
||||
|
||||
$requeststring = ($serverVars['REQUEST_METHOD'] ?? '') . ' ' . ($serverVars['REQUEST_URI'] ?? '') . ' ' . ($serverVars['SERVER_PROTOCOL'] ?? '');
|
||||
$this->logger->debug('Request received', ['address' => $serverVars['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $serverVars['HTTP_REFERER'] ?? '', 'user-agent' => $serverVars['HTTP_USER_AGENT'] ?? '']);
|
||||
$request_start = microtime(true);
|
||||
$request = $_REQUEST;
|
||||
|
||||
$this->profiler->set($start_time, 'start');
|
||||
$this->profiler->set(microtime(true), 'classinit');
|
||||
|
@ -536,54 +447,55 @@ class App
|
|||
|
||||
try {
|
||||
// Missing DB connection: ERROR
|
||||
if ($this->mode->has(App\Mode::LOCALCONFIGPRESENT) && !$this->mode->has(App\Mode::DBAVAILABLE)) {
|
||||
if ($this->mode->has(Mode::LOCALCONFIGPRESENT) && !$this->mode->has(Mode::DBAVAILABLE)) {
|
||||
throw new HTTPException\InternalServerErrorException($this->l10n->t('Apologies but the website is unavailable at the moment.'));
|
||||
}
|
||||
|
||||
if (!$this->mode->isInstall()) {
|
||||
// Force SSL redirection
|
||||
if ($this->config->get('system', 'force_ssl') &&
|
||||
(empty($server['HTTPS']) || $server['HTTPS'] === 'off') &&
|
||||
(empty($server['HTTP_X_FORWARDED_PROTO']) || $server['HTTP_X_FORWARDED_PROTO'] === 'http') &&
|
||||
!empty($server['REQUEST_METHOD']) &&
|
||||
$server['REQUEST_METHOD'] === 'GET') {
|
||||
(empty($serverVars['HTTPS']) || $serverVars['HTTPS'] === 'off') &&
|
||||
(empty($serverVars['HTTP_X_FORWARDED_PROTO']) || $serverVars['HTTP_X_FORWARDED_PROTO'] === 'http') &&
|
||||
!empty($serverVars['REQUEST_METHOD']) &&
|
||||
$serverVars['REQUEST_METHOD'] === 'GET') {
|
||||
System::externalRedirect($this->baseURL . '/' . $this->args->getQueryString());
|
||||
}
|
||||
Core\Hook::callAll('init_1');
|
||||
|
||||
$eventDispatcher->dispatch(new Event(Event::INIT));
|
||||
}
|
||||
|
||||
DID::routeRequest($this->args->getCommand(), $server);
|
||||
DID::routeRequest($this->args->getCommand(), $serverVars);
|
||||
|
||||
if ($this->mode->isNormal() && !$this->mode->isBackend()) {
|
||||
$requester = HTTPSignature::getSigner('', $server);
|
||||
$requester = HTTPSignature::getSigner('', $serverVars);
|
||||
if (!empty($requester)) {
|
||||
OpenWebAuth::addVisitorCookieForHandle($requester);
|
||||
}
|
||||
}
|
||||
|
||||
// ZRL
|
||||
if (!empty($_GET['zrl']) && $this->mode->isNormal() && !$this->mode->isBackend() && !$this->session->getLocalUserId()) {
|
||||
if (!empty($queryVars['zrl']) && $this->mode->isNormal() && !$this->mode->isBackend() && !$this->session->getLocalUserId()) {
|
||||
// Only continue when the given profile link seems valid.
|
||||
// Valid profile links contain a path with "/profile/" and no query parameters
|
||||
if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == '') &&
|
||||
strpos(parse_url($_GET['zrl'], PHP_URL_PATH) ?? '', '/profile/') !== false) {
|
||||
$this->auth->setUnauthenticatedVisitor($_GET['zrl']);
|
||||
if ((parse_url($queryVars['zrl'], PHP_URL_QUERY) == '') &&
|
||||
strpos(parse_url($queryVars['zrl'], PHP_URL_PATH) ?? '', '/profile/') !== false) {
|
||||
$this->auth->setUnauthenticatedVisitor($queryVars['zrl']);
|
||||
OpenWebAuth::zrlInit();
|
||||
} else {
|
||||
// Someone came with an invalid parameter, maybe as a DDoS attempt
|
||||
// We simply stop processing here
|
||||
$this->logger->debug('Invalid ZRL parameter.', ['zrl' => $_GET['zrl']]);
|
||||
$this->logger->debug('Invalid ZRL parameter.', ['zrl' => $queryVars['zrl']]);
|
||||
throw new HTTPException\ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_GET['owt']) && $this->mode->isNormal()) {
|
||||
$token = $_GET['owt'];
|
||||
if (!empty($queryVars['owt']) && $this->mode->isNormal()) {
|
||||
$token = $queryVars['owt'];
|
||||
OpenWebAuth::init($token);
|
||||
}
|
||||
|
||||
if (!$this->mode->isBackend()) {
|
||||
$auth->withSession($this);
|
||||
$this->auth->withSession();
|
||||
}
|
||||
|
||||
if ($this->session->isUnauthenticated()) {
|
||||
|
@ -600,12 +512,12 @@ class App
|
|||
// but we need "view" module for stylesheet
|
||||
if ($this->mode->isInstall() && $moduleName !== 'install') {
|
||||
$this->baseURL->redirect('install');
|
||||
} else {
|
||||
Core\Update::check($this->getBasePath(), false);
|
||||
Core\Addon::loadAddons();
|
||||
Core\Hook::loadHooks();
|
||||
}
|
||||
|
||||
Core\Update::check($this->appHelper->getBasePath(), false);
|
||||
$addonHelper->loadAddons();
|
||||
Core\Hook::loadHooks();
|
||||
|
||||
// Compatibility with Hubzilla
|
||||
if ($moduleName == 'rpost') {
|
||||
$this->baseURL->redirect('compose');
|
||||
|
@ -648,12 +560,12 @@ class App
|
|||
$page['page_title'] = $moduleName;
|
||||
|
||||
// The "view" module is required to show the theme CSS
|
||||
if (!$this->mode->isInstall() && !$this->mode->has(App\Mode::MAINTENANCEDISABLED) && $moduleName !== 'view') {
|
||||
$module = $router->getModule(Maintenance::class);
|
||||
if (!$this->mode->isInstall() && !$this->mode->has(Mode::MAINTENANCEDISABLED) && $moduleName !== 'view') {
|
||||
$module = $this->createModuleInstance(Maintenance::class);
|
||||
} else {
|
||||
// determine the module class and save it to the module instance
|
||||
// @todo there's an implicit dependency due SESSION::start(), so it has to be called here (yet)
|
||||
$module = $router->getModule();
|
||||
$module = $this->createModuleInstance(null);
|
||||
}
|
||||
|
||||
// Display can change depending on the requested language, so it shouldn't be cached whole
|
||||
|
@ -661,7 +573,15 @@ class App
|
|||
|
||||
// Processes data from GET requests
|
||||
$httpinput = $httpInput->process();
|
||||
$input = array_merge($httpinput['variables'], $httpinput['files'], $request ?? $_REQUEST);
|
||||
|
||||
if (!is_array($httpinput['variables'])) {
|
||||
$httpinput['variables'] = [];
|
||||
}
|
||||
if (!is_array($httpinput['files'])) {
|
||||
$httpinput['files'] = [];
|
||||
}
|
||||
|
||||
$input = array_merge($httpinput['variables'], $httpinput['files'], $request);
|
||||
|
||||
// Let the module run its internal process (init, get, post, ...)
|
||||
$timestamp = microtime(true);
|
||||
|
@ -670,37 +590,45 @@ class App
|
|||
|
||||
// Wrapping HTML responses in the theme template
|
||||
if ($response->getHeaderLine(ICanCreateResponses::X_HEADER) === ICanCreateResponses::TYPE_HTML) {
|
||||
$response = $page->run($this, $this->session, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $nav, $this->session->getLocalUserId());
|
||||
$response = $page->run($this->appHelper, $this->session, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $nav, $this->session->getLocalUserId());
|
||||
}
|
||||
|
||||
$this->logger->debug('Request processed sucessfully', ['response' => $response->getStatusCode(), 'address' => $server['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $server['HTTP_REFERER'] ?? '', 'user-agent' => $server['HTTP_USER_AGENT'] ?? '', 'duration' => number_format(microtime(true) - $request_start, 3)]);
|
||||
$this->logSlowCalls(microtime(true) - $request_start, $response->getStatusCode(), $requeststring, $server['HTTP_USER_AGENT'] ?? '');
|
||||
$this->logger->debug('Request processed sucessfully', ['response' => $response->getStatusCode(), 'address' => $serverVars['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $serverVars['HTTP_REFERER'] ?? '', 'user-agent' => $serverVars['HTTP_USER_AGENT'] ?? '', 'duration' => number_format(microtime(true) - $request_start, 3)]);
|
||||
$this->logSlowCalls(microtime(true) - $request_start, $response->getStatusCode(), $requeststring, $serverVars['HTTP_USER_AGENT'] ?? '');
|
||||
System::echoResponse($response);
|
||||
} catch (HTTPException $e) {
|
||||
$this->logger->debug('Request processed with exception', ['response' => $e->getCode(), 'address' => $server['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $server['HTTP_REFERER'] ?? '', 'user-agent' => $server['HTTP_USER_AGENT'] ?? '', 'duration' => number_format(microtime(true) - $request_start, 3)]);
|
||||
$this->logSlowCalls(microtime(true) - $request_start, $e->getCode(), $requeststring, $server['HTTP_USER_AGENT'] ?? '');
|
||||
$this->logger->debug('Request processed with exception', ['response' => $e->getCode(), 'address' => $serverVars['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $serverVars['HTTP_REFERER'] ?? '', 'user-agent' => $serverVars['HTTP_USER_AGENT'] ?? '', 'duration' => number_format(microtime(true) - $request_start, 3)]);
|
||||
$this->logSlowCalls(microtime(true) - $request_start, $e->getCode(), $requeststring, $serverVars['HTTP_USER_AGENT'] ?? '');
|
||||
$httpException->rawContent($e);
|
||||
}
|
||||
$page->logRuntime($this->config, 'runFrontend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically redirects to relative or absolute URL
|
||||
* Should only be used if it isn't clear if the URL is either internal or external
|
||||
*
|
||||
* @param string $toUrl The target URL
|
||||
*
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function redirect(string $toUrl)
|
||||
private function createModuleInstance(?string $moduleClass = null): ICanHandleRequests
|
||||
{
|
||||
if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) {
|
||||
Core\System::externalRedirect($toUrl);
|
||||
} else {
|
||||
$this->baseURL->redirect($toUrl);
|
||||
/** @var Router $router */
|
||||
$router = $this->container->create(Router::class);
|
||||
|
||||
$moduleClass = $moduleClass ?? $router->getModuleClass();
|
||||
$parameters = $router->getParameters();
|
||||
|
||||
$dice_profiler_threshold = $this->config->get('system', 'dice_profiler_threshold', 0);
|
||||
|
||||
$stamp = microtime(true);
|
||||
|
||||
/** @var ICanHandleRequests $module */
|
||||
$module = $this->container->create($moduleClass, $parameters);
|
||||
|
||||
if ($dice_profiler_threshold > 0) {
|
||||
$dur = floatval(microtime(true) - $stamp);
|
||||
if ($dur >= $dice_profiler_threshold) {
|
||||
$this->logger->notice('Dice module creation lasts too long.', ['duration' => round($dur, 3), 'module' => $moduleClass, 'parameters' => $parameters]);
|
||||
}
|
||||
}
|
||||
|
||||
return $module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log slow page executions
|
||||
*
|
||||
|
|
|
@ -17,8 +17,7 @@ use Psr\Http\Message\UriInterface;
|
|||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* A class which checks and contains the basic
|
||||
* environment for the BaseURL (url, urlpath, ssl_policy, hostname, scheme)
|
||||
* A class which checks and contains the basic environment for the BaseURL (url)
|
||||
*/
|
||||
class BaseURL extends Uri implements UriInterface
|
||||
{
|
||||
|
@ -43,8 +42,7 @@ class BaseURL extends Uri implements UriInterface
|
|||
/* Relative script path to the web server root
|
||||
* Not all of those $_SERVER properties can be present, so we do by inverse priority order
|
||||
*/
|
||||
$relativeScriptPath =
|
||||
($server['REDIRECT_URL'] ?? '') ?:
|
||||
$relativeScriptPath = ($server['REDIRECT_URL'] ?? '') ?:
|
||||
($server['REDIRECT_URI'] ?? '') ?:
|
||||
($server['REDIRECT_SCRIPT_URL'] ?? '') ?:
|
||||
($server['SCRIPT_URL'] ?? '') ?:
|
||||
|
@ -103,6 +101,8 @@ class BaseURL extends Uri implements UriInterface
|
|||
* @throws HTTPException\TemporaryRedirectException
|
||||
*
|
||||
* @throws HTTPException\InternalServerErrorException In Case the given URL is not relative to the Friendica node
|
||||
*
|
||||
* @return never
|
||||
*/
|
||||
public function redirect(string $toUrl = '', bool $ssl = false)
|
||||
{
|
||||
|
|
|
@ -210,7 +210,7 @@ class Mode
|
|||
public function isInstall(): bool
|
||||
{
|
||||
return !$this->has(Mode::LOCALCONFIGPRESENT) ||
|
||||
!$this->has(MODE::DBAVAILABLE);
|
||||
!$this->has(Mode::DBAVAILABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,23 +11,24 @@ use ArrayAccess;
|
|||
use DOMDocument;
|
||||
use DOMXPath;
|
||||
use Friendica\App;
|
||||
use Friendica\AppHelper;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Session\Model\UserSession;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Theme;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\DI;
|
||||
use Friendica\Event\HtmlFilterEvent;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Strings;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
|
@ -70,6 +71,8 @@ class Page implements ArrayAccess
|
|||
*/
|
||||
private $basePath;
|
||||
|
||||
private EventDispatcherInterface $eventDispatcher;
|
||||
|
||||
private $timestamp = 0;
|
||||
private $method = '';
|
||||
private $module = '';
|
||||
|
@ -78,10 +81,11 @@ class Page implements ArrayAccess
|
|||
/**
|
||||
* @param string $basepath The Page basepath
|
||||
*/
|
||||
public function __construct(string $basepath)
|
||||
public function __construct(string $basepath, EventDispatcherInterface $eventDispatcher)
|
||||
{
|
||||
$this->timestamp = microtime(true);
|
||||
$this->basePath = $basepath;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
}
|
||||
|
||||
public function setLogging(string $method, string $module, string $command)
|
||||
|
@ -102,7 +106,7 @@ class Page implements ArrayAccess
|
|||
$load = number_format(System::currentLoad(), 2);
|
||||
$runtime = number_format(microtime(true) - $this->timestamp, 3);
|
||||
if ($runtime > $config->get('system', 'runtime_loglimit')) {
|
||||
Logger::debug('Runtime', ['method' => $this->method, 'module' => $this->module, 'runtime' => $runtime, 'load' => $load, 'origin' => $origin, 'signature' => $signature, 'request' => $_SERVER['REQUEST_URI'] ?? '']);
|
||||
DI::logger()->debug('Runtime', ['method' => $this->method, 'module' => $this->module, 'runtime' => $runtime, 'load' => $load, 'origin' => $origin, 'signature' => $signature, 'request' => $_SERVER['REQUEST_URI'] ?? '']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,7 +180,6 @@ class Page implements ArrayAccess
|
|||
* - Infinite scroll data
|
||||
* - head.tpl template
|
||||
*
|
||||
* @param App $app The Friendica App instance
|
||||
* @param Arguments $args The Friendica App Arguments
|
||||
* @param L10n $l10n The l10n language instance
|
||||
* @param IManageConfigValues $config The Friendica configuration
|
||||
|
@ -185,31 +188,26 @@ class Page implements ArrayAccess
|
|||
*
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private function initHead(App $app, Arguments $args, L10n $l10n, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, int $localUID)
|
||||
{
|
||||
$interval = ($localUID ? $pConfig->get($localUID, 'system', 'update_interval') : 40000);
|
||||
|
||||
// If the update is 'deactivated' set it to the highest integer number (~24 days)
|
||||
if ($interval < 0) {
|
||||
$interval = 2147483647;
|
||||
}
|
||||
|
||||
if ($interval < 10000) {
|
||||
$interval = 40000;
|
||||
}
|
||||
|
||||
private function initHead(
|
||||
AppHelper $appHelper,
|
||||
Arguments $args,
|
||||
L10n $l10n,
|
||||
IManageConfigValues $config,
|
||||
IManagePersonalConfigValues $pConfig,
|
||||
int $localUID
|
||||
) {
|
||||
// Default title: current module called
|
||||
if (empty($this->page['title']) && $args->getModuleName()) {
|
||||
$this->page['title'] = ucfirst($args->getModuleName());
|
||||
$this->page['title'] = $l10n->t(ucfirst($args->getModuleName()));
|
||||
}
|
||||
|
||||
// Prepend the sitename to the page title
|
||||
$this->page['title'] = $config->get('config', 'sitename', '') . (!empty($this->page['title']) ? ' | ' . $this->page['title'] : '');
|
||||
// Append the sitename to the page title
|
||||
$this->page['title'] = (!empty($this->page['title']) ? $this->page['title'] . ' | ' : '') . $config->get('config', 'sitename', '');
|
||||
|
||||
if (!empty(Renderer::$theme['stylesheet'])) {
|
||||
$stylesheet = Renderer::$theme['stylesheet'];
|
||||
} else {
|
||||
$stylesheet = $app->getCurrentThemeStylesheetPath();
|
||||
$stylesheet = $appHelper->getCurrentThemeStylesheetPath();
|
||||
}
|
||||
|
||||
$this->registerStylesheet($stylesheet);
|
||||
|
@ -224,7 +222,9 @@ class Page implements ArrayAccess
|
|||
$touch_icon = 'images/friendica-192.png';
|
||||
}
|
||||
|
||||
Hook::callAll('head', $this->page['htmlhead']);
|
||||
$this->page['htmlhead'] = $this->eventDispatcher->dispatch(
|
||||
new HtmlFilterEvent(HtmlFilterEvent::HEAD, $this->page['htmlhead'])
|
||||
)->getHtml();
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('head.tpl');
|
||||
/* put the head template at the beginning of page['htmlhead']
|
||||
|
@ -263,7 +263,7 @@ class Page implements ArrayAccess
|
|||
|
||||
'$local_user' => $localUID,
|
||||
'$generator' => 'Friendica' . ' ' . App::VERSION,
|
||||
'$update_interval' => $interval,
|
||||
'$update_content' => (int)$pConfig->get($localUID, 'system', 'update_content'),
|
||||
'$shortcut_icon' => $shortcut_icon,
|
||||
'$touch_icon' => $touch_icon,
|
||||
'$block_public' => intval($config->get('system', 'block_public')),
|
||||
|
@ -313,7 +313,6 @@ class Page implements ArrayAccess
|
|||
* - Registered footer scripts (through App->registerFooterScript())
|
||||
* - footer.tpl template
|
||||
*
|
||||
* @param App $app The Friendica App instance
|
||||
* @param Mode $mode The Friendica runtime mode
|
||||
* @param L10n $l10n The l10n instance
|
||||
*
|
||||
|
@ -347,11 +346,14 @@ class Page implements ArrayAccess
|
|||
]);
|
||||
}
|
||||
|
||||
Hook::callAll('footer', $this->page['footer']);
|
||||
$this->page['footer'] = $this->eventDispatcher->dispatch(
|
||||
new HtmlFilterEvent(HtmlFilterEvent::FOOTER, $this->page['footer'])
|
||||
)->getHtml();
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('footer.tpl');
|
||||
$this->page['footer'] = Renderer::replaceMacros($tpl, [
|
||||
'$footerScripts' => array_unique($this->footerScripts),
|
||||
'$close' => $l10n->t('Close'),
|
||||
]) . $this->page['footer'];
|
||||
}
|
||||
|
||||
|
@ -371,7 +373,9 @@ class Page implements ArrayAccess
|
|||
{
|
||||
// initialise content region
|
||||
if ($mode->isNormal()) {
|
||||
Hook::callAll('page_content_top', $this->page['content']);
|
||||
$this->page['content'] = $this->eventDispatcher->dispatch(
|
||||
new HtmlFilterEvent(HtmlFilterEvent::PAGE_CONTENT_TOP, $this->page['content'])
|
||||
)->getHtml();
|
||||
}
|
||||
|
||||
$this->page['content'] .= (string)$response->getBody();
|
||||
|
@ -399,7 +403,6 @@ class Page implements ArrayAccess
|
|||
/**
|
||||
* Executes the creation of the current page and prints it to the screen
|
||||
*
|
||||
* @param App $app The Friendica App
|
||||
* @param BaseURL $baseURL The Friendica Base URL
|
||||
* @param Arguments $args The Friendica App arguments
|
||||
* @param Mode $mode The current node mode
|
||||
|
@ -414,8 +417,20 @@ class Page implements ArrayAccess
|
|||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\ServiceUnavailableException
|
||||
*/
|
||||
public function run(App $app, UserSession $session, BaseURL $baseURL, Arguments $args, Mode $mode, ResponseInterface $response, L10n $l10n, Profiler $profiler, IManageConfigValues $config, IManagePersonalConfigValues $pconfig, Nav $nav, int $localUID)
|
||||
{
|
||||
public function run(
|
||||
AppHelper $appHelper,
|
||||
UserSession $session,
|
||||
BaseURL $baseURL,
|
||||
Arguments $args,
|
||||
Mode $mode,
|
||||
ResponseInterface $response,
|
||||
L10n $l10n,
|
||||
Profiler $profiler,
|
||||
IManageConfigValues $config,
|
||||
IManagePersonalConfigValues $pconfig,
|
||||
Nav $nav,
|
||||
int $localUID
|
||||
) {
|
||||
$moduleName = $args->getModuleName();
|
||||
|
||||
$this->command = $moduleName;
|
||||
|
@ -430,7 +445,7 @@ class Page implements ArrayAccess
|
|||
$this->initContent($response, $mode);
|
||||
|
||||
// Load current theme info after module has been initialized as theme could have been set in module
|
||||
$currentTheme = $app->getCurrentTheme();
|
||||
$currentTheme = $appHelper->getCurrentTheme();
|
||||
$theme_info_file = 'view/theme/' . $currentTheme . '/theme.php';
|
||||
if (file_exists($theme_info_file)) {
|
||||
require_once $theme_info_file;
|
||||
|
@ -438,7 +453,7 @@ class Page implements ArrayAccess
|
|||
|
||||
if (function_exists(str_replace('-', '_', $currentTheme) . '_init')) {
|
||||
$func = str_replace('-', '_', $currentTheme) . '_init';
|
||||
$func($app);
|
||||
$func($appHelper);
|
||||
}
|
||||
|
||||
/* Create the page head after setting the language
|
||||
|
@ -448,7 +463,7 @@ class Page implements ArrayAccess
|
|||
* all the module functions have executed so that all
|
||||
* theme choices made by the modules can take effect.
|
||||
*/
|
||||
$this->initHead($app, $args, $l10n, $config, $pconfig, $localUID);
|
||||
$this->initHead($appHelper, $args, $l10n, $config, $pconfig, $localUID);
|
||||
|
||||
/* Build the page ending -- this is stuff that goes right before
|
||||
* the closing </body> tag
|
||||
|
@ -458,7 +473,9 @@ class Page implements ArrayAccess
|
|||
$profiler->set(microtime(true) - $timestamp, 'aftermath');
|
||||
|
||||
if (!$mode->isAjax()) {
|
||||
Hook::callAll('page_end', $this->page['content']);
|
||||
$this->page['content'] = $this->eventDispatcher->dispatch(
|
||||
new HtmlFilterEvent(HtmlFilterEvent::PAGE_END, $this->page['content'])
|
||||
)->getHtml();
|
||||
}
|
||||
|
||||
// Add the navigation (menu) template
|
||||
|
@ -534,7 +551,7 @@ class Page implements ArrayAccess
|
|||
}
|
||||
|
||||
// Theme templates expect $a as an App instance
|
||||
$a = $app;
|
||||
$a = $appHelper;
|
||||
|
||||
// Used as is in view/php/default.php
|
||||
$lang = $l10n->getCurrentLang();
|
||||
|
|
|
@ -7,13 +7,11 @@
|
|||
|
||||
namespace Friendica\App;
|
||||
|
||||
use Dice\Dice;
|
||||
use FastRoute\DataGenerator\GroupCountBased;
|
||||
use FastRoute\Dispatcher;
|
||||
use FastRoute\RouteCollector;
|
||||
use FastRoute\RouteParser\Std;
|
||||
use Friendica\Capabilities\ICanHandleRequests;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Addon\AddonHelper;
|
||||
use Friendica\Core\Cache\Enum\Duration;
|
||||
use Friendica\Core\Cache\Capability\ICanCache;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
|
@ -21,6 +19,7 @@ use Friendica\Core\Hook;
|
|||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Event\CollectRoutesEvent;
|
||||
use Friendica\LegacyModule;
|
||||
use Friendica\Module\HTTPException\MethodNotAllowed;
|
||||
use Friendica\Module\HTTPException\PageNotFound;
|
||||
|
@ -30,6 +29,7 @@ use Friendica\Network\HTTPException\InternalServerErrorException;
|
|||
use Friendica\Network\HTTPException\MethodNotAllowedException;
|
||||
use Friendica\Network\HTTPException\NotFoundException;
|
||||
use Friendica\Util\Router\FriendicaGroupCountBased;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
|
@ -86,15 +86,13 @@ class Router
|
|||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
private EventDispatcherInterface $eventDispatcher;
|
||||
|
||||
private AddonHelper $addonHelper;
|
||||
|
||||
/** @var bool */
|
||||
private $isLocalUser;
|
||||
|
||||
/** @var float */
|
||||
private $dice_profiler_threshold;
|
||||
|
||||
/** @var Dice */
|
||||
private $dice;
|
||||
|
||||
/** @var string */
|
||||
private $baseRoutesFilepath;
|
||||
|
||||
|
@ -113,11 +111,10 @@ class Router
|
|||
* @param IManageConfigValues $config
|
||||
* @param Arguments $args
|
||||
* @param LoggerInterface $logger
|
||||
* @param Dice $dice
|
||||
* @param IHandleUserSessions $userSession
|
||||
* @param RouteCollector|null $routeCollector
|
||||
*/
|
||||
public function __construct(array $server, string $baseRoutesFilepath, L10n $l10n, ICanCache $cache, ICanLock $lock, IManageConfigValues $config, Arguments $args, LoggerInterface $logger, Dice $dice, IHandleUserSessions $userSession, RouteCollector $routeCollector = null)
|
||||
public function __construct(array $server, string $baseRoutesFilepath, L10n $l10n, ICanCache $cache, ICanLock $lock, IManageConfigValues $config, Arguments $args, LoggerInterface $logger, EventDispatcherInterface $eventDispatcher, AddonHelper $addonHelper, IHandleUserSessions $userSession, RouteCollector $routeCollector = null)
|
||||
{
|
||||
$this->baseRoutesFilepath = $baseRoutesFilepath;
|
||||
$this->l10n = $l10n;
|
||||
|
@ -125,11 +122,11 @@ class Router
|
|||
$this->lock = $lock;
|
||||
$this->args = $args;
|
||||
$this->config = $config;
|
||||
$this->dice = $dice;
|
||||
$this->server = $server;
|
||||
$this->logger = $logger;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->addonHelper = $addonHelper;
|
||||
$this->isLocalUser = !empty($userSession->getLocalUserId());
|
||||
$this->dice_profiler_threshold = $config->get('system', 'dice_profiler_threshold', 0);
|
||||
|
||||
$this->routeCollector = $routeCollector ?? new RouteCollector(new Std(), new GroupCountBased());
|
||||
|
||||
|
@ -156,10 +153,12 @@ class Router
|
|||
|
||||
$this->addRoutes($routeCollector, $routes);
|
||||
|
||||
$this->routeCollector = $routeCollector;
|
||||
|
||||
// Add routes from addons
|
||||
Hook::callAll('route_collection', $this->routeCollector);
|
||||
$routeCollector = $this->eventDispatcher->dispatch(
|
||||
new CollectRoutesEvent(CollectRoutesEvent::COLLECT_ROUTES, $routeCollector),
|
||||
)->getRouteCollector();
|
||||
|
||||
$this->routeCollector = $routeCollector;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -302,7 +301,7 @@ class Router
|
|||
} catch (NotFoundException $e) {
|
||||
$moduleName = $this->args->getModuleName();
|
||||
// Then we try addon-provided modules that we wrap in the LegacyModule class
|
||||
if (Addon::isEnabled($moduleName) && file_exists("addon/{$moduleName}/{$moduleName}.php")) {
|
||||
if ($this->addonHelper->isAddonEnabled($moduleName) && file_exists("addon/{$moduleName}/{$moduleName}.php")) {
|
||||
//Check if module is an app and if public access to apps is allowed or not
|
||||
$privateapps = $this->config->get('config', 'private_addons', false);
|
||||
if (!$this->isLocalUser && Hook::isAddonApp($moduleName) && $privateapps) {
|
||||
|
@ -328,23 +327,9 @@ class Router
|
|||
}
|
||||
}
|
||||
|
||||
public function getModule(?string $module_class = null): ICanHandleRequests
|
||||
public function getParameters(): array
|
||||
{
|
||||
$moduleClass = $module_class ?? $this->getModuleClass();
|
||||
|
||||
$stamp = microtime(true);
|
||||
|
||||
try {
|
||||
/** @var ICanHandleRequests $module */
|
||||
return $this->dice->create($moduleClass, $this->parameters);
|
||||
} finally {
|
||||
if ($this->dice_profiler_threshold > 0) {
|
||||
$dur = floatval(microtime(true) - $stamp);
|
||||
if ($dur >= $this->dice_profiler_threshold) {
|
||||
$this->logger->notice('Dice module creation lasts too long.', ['duration' => round($dur, 3), 'module' => $moduleClass, 'parameters' => $this->parameters]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
139
src/AppHelper.php
Normal file
139
src/AppHelper.php
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
namespace Friendica;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Core\Config\ValueObject\Cache;
|
||||
|
||||
/**
|
||||
* Helper for our main application structure for the life of this page.
|
||||
*
|
||||
* Primarily deals with the URL that got us here
|
||||
* and tries to make some sense of it, and
|
||||
* stores our page contents and config storage
|
||||
* and anything else that might need to be passed around
|
||||
* before we spit the page out.
|
||||
*
|
||||
*/
|
||||
interface AppHelper
|
||||
{
|
||||
/**
|
||||
* Set the profile owner ID
|
||||
*/
|
||||
public function setProfileOwner(int $owner_id);
|
||||
|
||||
/**
|
||||
* Get the profile owner ID
|
||||
*/
|
||||
public function getProfileOwner(): int;
|
||||
|
||||
/**
|
||||
* Set the timezone
|
||||
*
|
||||
* @param string $timezone A valid time zone identifier, see https://www.php.net/manual/en/timezones.php
|
||||
*/
|
||||
public function setTimeZone(string $timezone);
|
||||
|
||||
/**
|
||||
* Get the timezone name
|
||||
*/
|
||||
public function getTimeZone(): string;
|
||||
|
||||
/**
|
||||
* Set the contact ID
|
||||
*/
|
||||
public function setContactId(int $contact_id);
|
||||
|
||||
/**
|
||||
* Get the contact ID
|
||||
*/
|
||||
public function getContactId(): int;
|
||||
|
||||
/**
|
||||
* Set workerqueue information
|
||||
*
|
||||
* @param array<string,mixed> $queue
|
||||
*/
|
||||
public function setQueue(array $queue);
|
||||
|
||||
/**
|
||||
* Fetch workerqueue information
|
||||
*
|
||||
* @return array<string,mixed> Worker queue
|
||||
*/
|
||||
public function getQueue();
|
||||
|
||||
/**
|
||||
* Fetch a specific workerqueue field
|
||||
*
|
||||
* @param string $index Work queue record to fetch
|
||||
*
|
||||
* @return mixed|null Work queue item or NULL if not found
|
||||
*/
|
||||
public function getQueueValue(string $index);
|
||||
|
||||
/**
|
||||
* Returns the current theme name. May be overridden by the mobile theme name.
|
||||
*
|
||||
* @return string Current theme name or empty string in installation phase
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentTheme(): string;
|
||||
|
||||
/**
|
||||
* Returns the current mobile theme name.
|
||||
*
|
||||
* @return string Mobile theme name or empty string if installer
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentMobileTheme(): string;
|
||||
|
||||
/**
|
||||
* Setter for current theme name
|
||||
*
|
||||
* @param string $theme Name of current theme
|
||||
*/
|
||||
public function setCurrentTheme(string $theme);
|
||||
|
||||
/**
|
||||
* Setter for current mobile theme name
|
||||
*
|
||||
* @param string $theme Name of current mobile theme
|
||||
*/
|
||||
public function setCurrentMobileTheme(string $theme);
|
||||
|
||||
public function setThemeInfoValue(string $index, $value);
|
||||
|
||||
public function getThemeInfo();
|
||||
|
||||
public function getThemeInfoValue(string $index, $default = null);
|
||||
|
||||
/**
|
||||
* Provide a sane default if nothing is chosen or the specified theme does not exist.
|
||||
*
|
||||
* @return string Current theme's stylesheet path
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentThemeStylesheetPath(): string;
|
||||
|
||||
/**
|
||||
* Returns the current config cache of this node
|
||||
*
|
||||
* @return Cache
|
||||
*/
|
||||
public function getConfigCache();
|
||||
|
||||
/**
|
||||
* The basepath of this app
|
||||
*
|
||||
* @return string Base path from configuration
|
||||
*/
|
||||
public function getBasePath(): string;
|
||||
|
||||
public function redirect(string $toUrl);
|
||||
}
|
400
src/AppLegacy.php
Normal file
400
src/AppLegacy.php
Normal file
|
@ -0,0 +1,400 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
namespace Friendica;
|
||||
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Config\ValueObject\Cache;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Theme;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
/**
|
||||
* Helper for our main application structure for the life of this page.
|
||||
*
|
||||
* Primarily deals with the URL that got us here
|
||||
* and tries to make some sense of it, and
|
||||
* stores our page contents and config storage
|
||||
* and anything else that might need to be passed around
|
||||
* before we spit the page out.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class AppLegacy implements AppHelper
|
||||
{
|
||||
private $profile_owner = 0;
|
||||
|
||||
private $timezone = '';
|
||||
|
||||
private $contact_id = 0;
|
||||
|
||||
private $queue = [];
|
||||
|
||||
/** @var string The name of the current theme */
|
||||
private $currentTheme;
|
||||
|
||||
/** @var string The name of the current mobile theme */
|
||||
private $currentMobileTheme;
|
||||
|
||||
// Allow themes to control internal parameters
|
||||
// by changing App values in theme.php
|
||||
private $theme_info = [
|
||||
'videowidth' => 425,
|
||||
'videoheight' => 350,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var Database The Friendica database connection
|
||||
*/
|
||||
private $database;
|
||||
|
||||
/**
|
||||
* @var IManageConfigValues The config
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var Mode The Mode of the Application
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* @var BaseURL
|
||||
*/
|
||||
private $baseURL;
|
||||
|
||||
/**
|
||||
* @var L10n The translator
|
||||
*/
|
||||
private $l10n;
|
||||
|
||||
/**
|
||||
* @var IManagePersonalConfigValues
|
||||
*/
|
||||
private $pConfig;
|
||||
|
||||
/**
|
||||
* @var IHandleUserSessions
|
||||
*/
|
||||
private $session;
|
||||
|
||||
public function __construct(
|
||||
Database $database,
|
||||
IManageConfigValues $config,
|
||||
Mode $mode,
|
||||
BaseURL $baseURL,
|
||||
L10n $l10n,
|
||||
IManagePersonalConfigValues $pConfig,
|
||||
IHandleUserSessions $session
|
||||
) {
|
||||
$this->database = $database;
|
||||
$this->config = $config;
|
||||
$this->mode = $mode;
|
||||
$this->l10n = $l10n;
|
||||
$this->baseURL = $baseURL;
|
||||
$this->pConfig = $pConfig;
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the profile owner ID
|
||||
*/
|
||||
public function setProfileOwner(int $owner_id): void
|
||||
{
|
||||
$this->profile_owner = $owner_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the profile owner ID
|
||||
*/
|
||||
public function getProfileOwner(): int
|
||||
{
|
||||
return $this->profile_owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timezone
|
||||
*
|
||||
* @param string $timezone A valid time zone identifier, see https://www.php.net/manual/en/timezones.php
|
||||
*/
|
||||
public function setTimeZone(string $timezone): void
|
||||
{
|
||||
$this->timezone = (new DateTimeZone($timezone))->getName();
|
||||
|
||||
DateTimeFormat::setLocalTimeZone($this->timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timezone name
|
||||
*/
|
||||
public function getTimeZone(): string
|
||||
{
|
||||
return $this->timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the contact ID
|
||||
*/
|
||||
public function setContactId(int $contact_id): void
|
||||
{
|
||||
$this->contact_id = $contact_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contact ID
|
||||
*/
|
||||
public function getContactId(): int
|
||||
{
|
||||
return $this->contact_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set workerqueue information
|
||||
*
|
||||
* @param array<string,mixed> $queue
|
||||
*/
|
||||
public function setQueue(array $queue): void
|
||||
{
|
||||
$this->queue = $queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch workerqueue information
|
||||
*
|
||||
* @return array<string,mixed> Worker queue
|
||||
*/
|
||||
public function getQueue(): array
|
||||
{
|
||||
return $this->queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific workerqueue field
|
||||
*
|
||||
* @param string $index Work queue record to fetch
|
||||
*
|
||||
* @return mixed|null Work queue item or NULL if not found
|
||||
*/
|
||||
public function getQueueValue(string $index)
|
||||
{
|
||||
return $this->queue[$index] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current theme name. May be overridden by the mobile theme name.
|
||||
*
|
||||
* @return string Current theme name or empty string in installation phase
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentTheme(): string
|
||||
{
|
||||
if ($this->mode->isInstall()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Specific mobile theme override
|
||||
if (($this->mode->isMobile() || $this->mode->isTablet()) && $this->session->get('show-mobile', true)) {
|
||||
$user_mobile_theme = $this->getCurrentMobileTheme();
|
||||
|
||||
// --- means same mobile theme as desktop
|
||||
if (!empty($user_mobile_theme) && $user_mobile_theme !== '---') {
|
||||
return $user_mobile_theme;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->currentTheme) {
|
||||
$this->computeCurrentTheme();
|
||||
}
|
||||
|
||||
return $this->currentTheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current mobile theme name.
|
||||
*
|
||||
* @return string Mobile theme name or empty string if installer
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentMobileTheme(): string
|
||||
{
|
||||
if ($this->mode->isInstall()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (is_null($this->currentMobileTheme)) {
|
||||
$this->computeCurrentMobileTheme();
|
||||
}
|
||||
|
||||
return $this->currentMobileTheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for current theme name
|
||||
*
|
||||
* @param string $theme Name of current theme
|
||||
*/
|
||||
public function setCurrentTheme(string $theme): void
|
||||
{
|
||||
$this->currentTheme = $theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for current mobile theme name
|
||||
*
|
||||
* @param string $theme Name of current mobile theme
|
||||
*/
|
||||
public function setCurrentMobileTheme(string $theme): void
|
||||
{
|
||||
$this->currentMobileTheme = $theme;
|
||||
}
|
||||
|
||||
public function setThemeInfoValue(string $index, $value): void
|
||||
{
|
||||
$this->theme_info[$index] = $value;
|
||||
}
|
||||
|
||||
public function getThemeInfo(): array
|
||||
{
|
||||
return $this->theme_info;
|
||||
}
|
||||
|
||||
public function getThemeInfoValue(string $index, $default = null)
|
||||
{
|
||||
return $this->theme_info[$index] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a sane default if nothing is chosen or the specified theme does not exist.
|
||||
*
|
||||
* @return string Current theme's stylesheet path
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCurrentThemeStylesheetPath(): string
|
||||
{
|
||||
return Theme::getStylesheetPath($this->getCurrentTheme());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current config cache of this node
|
||||
*/
|
||||
public function getConfigCache(): Cache
|
||||
{
|
||||
return $this->config->getCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* The basepath of this app
|
||||
*
|
||||
* @return string Base path from configuration
|
||||
*/
|
||||
public function getBasePath(): string
|
||||
{
|
||||
return $this->config->get('system', 'basepath');
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the current theme name based on the node settings, the page owner settings and the user settings
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function computeCurrentTheme()
|
||||
{
|
||||
$system_theme = $this->config->get('system', 'theme');
|
||||
if (!$system_theme) {
|
||||
throw new Exception($this->l10n->t('No system theme config value set.'));
|
||||
}
|
||||
|
||||
// Sane default
|
||||
$this->setCurrentTheme($system_theme);
|
||||
|
||||
$page_theme = null;
|
||||
$profile_owner = $this->getProfileOwner();
|
||||
|
||||
// Find the theme that belongs to the user whose stuff we are looking at
|
||||
if (!empty($profile_owner) && ($profile_owner != $this->session->getLocalUserId())) {
|
||||
// Allow folks to override user themes and always use their own on their own site.
|
||||
// This works only if the user is on the same server
|
||||
$user = $this->database->selectFirst('user', ['theme'], ['uid' => $profile_owner]);
|
||||
if ($this->database->isResult($user) && !$this->session->getLocalUserId()) {
|
||||
$page_theme = $user['theme'];
|
||||
}
|
||||
}
|
||||
|
||||
$theme_name = $page_theme ?: $this->session->get('theme', $system_theme);
|
||||
|
||||
$theme_name = Strings::sanitizeFilePathItem($theme_name);
|
||||
if ($theme_name
|
||||
&& in_array($theme_name, Theme::getAllowedList())
|
||||
&& (file_exists('view/theme/' . $theme_name . '/style.css')
|
||||
|| file_exists('view/theme/' . $theme_name . '/style.php'))
|
||||
) {
|
||||
$this->setCurrentTheme($theme_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the current mobile theme name based on the node settings, the page owner settings and the user settings
|
||||
*/
|
||||
private function computeCurrentMobileTheme()
|
||||
{
|
||||
$system_mobile_theme = $this->config->get('system', 'mobile-theme', '');
|
||||
|
||||
// Sane default
|
||||
$this->setCurrentMobileTheme($system_mobile_theme);
|
||||
|
||||
$page_mobile_theme = null;
|
||||
$profile_owner = $this->getProfileOwner();
|
||||
|
||||
// Find the theme that belongs to the user whose stuff we are looking at
|
||||
if (!empty($profile_owner) && ($profile_owner != $this->session->getLocalUserId())) {
|
||||
// Allow folks to override user themes and always use their own on their own site.
|
||||
// This works only if the user is on the same server
|
||||
if (!$this->session->getLocalUserId()) {
|
||||
$page_mobile_theme = $this->pConfig->get($profile_owner, 'system', 'mobile-theme');
|
||||
}
|
||||
}
|
||||
|
||||
$mobile_theme_name = $page_mobile_theme ?: $this->session->get('mobile-theme', $system_mobile_theme);
|
||||
|
||||
$mobile_theme_name = Strings::sanitizeFilePathItem($mobile_theme_name);
|
||||
if ($mobile_theme_name == '---'
|
||||
||
|
||||
in_array($mobile_theme_name, Theme::getAllowedList())
|
||||
&& (file_exists('view/theme/' . $mobile_theme_name . '/style.css')
|
||||
|| file_exists('view/theme/' . $mobile_theme_name . '/style.php'))
|
||||
) {
|
||||
$this->setCurrentMobileTheme($mobile_theme_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically redirects to relative or absolute URL
|
||||
* Should only be used if it isn't clear if the URL is either internal or external
|
||||
*
|
||||
* @param string $toUrl The target URL
|
||||
*
|
||||
* @throws InternalServerErrorException
|
||||
*/
|
||||
public function redirect(string $toUrl)
|
||||
{
|
||||
if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) {
|
||||
System::externalRedirect($toUrl);
|
||||
} else {
|
||||
$this->baseURL->redirect($toUrl);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ class BaseCollection extends \ArrayIterator
|
|||
* @param BaseEntity[] $entities
|
||||
* @param int|null $totalCount
|
||||
*/
|
||||
public function __construct(array $entities = [], int $totalCount = null)
|
||||
public function __construct(array $entities = [], ?int $totalCount = null)
|
||||
{
|
||||
parent::__construct($entities);
|
||||
|
||||
|
@ -89,7 +89,9 @@ class BaseCollection extends \ArrayIterator
|
|||
*/
|
||||
public function map(callable $callback): BaseCollection
|
||||
{
|
||||
return new static(array_map($callback, $this->getArrayCopy()), $this->getTotalCount());
|
||||
$class = get_class($this);
|
||||
|
||||
return new $class(array_map($callback, $this->getArrayCopy()), $this->getTotalCount());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,26 +102,27 @@ class BaseCollection extends \ArrayIterator
|
|||
* @return BaseCollection
|
||||
* @see array_filter()
|
||||
*/
|
||||
public function filter(callable $callback = null, int $flag = 0): BaseCollection
|
||||
public function filter(?callable $callback = null, int $flag = 0): BaseCollection
|
||||
{
|
||||
return new static(array_filter($this->getArrayCopy(), $callback, $flag));
|
||||
$class = get_class($this);
|
||||
|
||||
return new $class(array_filter($this->getArrayCopy(), $callback, $flag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the orders of the elements in the collection
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reverse(): BaseCollection
|
||||
{
|
||||
return new static(array_reverse($this->getArrayCopy()), $this->getTotalCount());
|
||||
$class = get_class($this);
|
||||
|
||||
return new $class(array_reverse($this->getArrayCopy()), $this->getTotalCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the collection in smaller collections no bigger than the provided length
|
||||
*
|
||||
* @param int $length
|
||||
* @return static[]
|
||||
*/
|
||||
public function chunk(int $length): array
|
||||
{
|
||||
|
@ -127,9 +130,14 @@ class BaseCollection extends \ArrayIterator
|
|||
throw new \RangeException('BaseCollection->chunk(): Size parameter expected to be greater than 0');
|
||||
}
|
||||
|
||||
return array_map(function ($array) {
|
||||
return new static($array);
|
||||
}, array_chunk($this->getArrayCopy(), $length));
|
||||
return array_map(
|
||||
function ($array) {
|
||||
$class = get_class($this);
|
||||
|
||||
return new $class($array);
|
||||
},
|
||||
array_chunk($this->getArrayCopy(), $length)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Friendica;
|
||||
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
|
||||
/**
|
||||
* The Entity classes directly inheriting from this abstract class are meant to represent a single business entity.
|
||||
|
@ -29,12 +29,12 @@ abstract class BaseEntity extends BaseDataTransferObject
|
|||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws InternalServerErrorException
|
||||
*/
|
||||
public function __get(string $name)
|
||||
{
|
||||
if (!property_exists($this, $name)) {
|
||||
throw new HTTPException\InternalServerErrorException('Unknown property ' . $name . ' in Entity ' . static::class);
|
||||
throw new InternalServerErrorException('Unknown property ' . $name . ' in Entity ' . static::class);
|
||||
}
|
||||
|
||||
return $this->$name;
|
||||
|
@ -43,12 +43,12 @@ abstract class BaseEntity extends BaseDataTransferObject
|
|||
/**
|
||||
* @param mixed $name
|
||||
* @return bool
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws InternalServerErrorException
|
||||
*/
|
||||
public function __isset($name): bool
|
||||
{
|
||||
if (!property_exists($this, $name)) {
|
||||
throw new HTTPException\InternalServerErrorException('Unknown property ' . $name . ' of type ' . gettype($name) . ' in Entity ' . static::class);
|
||||
throw new InternalServerErrorException('Unknown property ' . $name . ' of type ' . gettype($name) . ' in Entity ' . static::class);
|
||||
}
|
||||
|
||||
return !empty($this->$name);
|
||||
|
|
|
@ -15,7 +15,7 @@ use Psr\Log\LoggerInterface;
|
|||
* The Model classes inheriting from this abstract class are meant to represent a single database record.
|
||||
* The associated table name has to be provided in the child class, and the table is expected to have a unique `id` field.
|
||||
*
|
||||
* @property int id
|
||||
* @property int $id
|
||||
*/
|
||||
abstract class BaseModel extends BaseDataTransferObject
|
||||
{
|
||||
|
@ -41,8 +41,6 @@ abstract class BaseModel extends BaseDataTransferObject
|
|||
private $originalData = [];
|
||||
|
||||
/**
|
||||
* @param Database $dba
|
||||
* @param LoggerInterface $logger
|
||||
* @param array $data Table row attributes
|
||||
*/
|
||||
public function __construct(Database $dba, LoggerInterface $logger, array $data = [])
|
||||
|
|
|
@ -12,7 +12,6 @@ use Friendica\Capabilities\ICanHandleRequests;
|
|||
use Friendica\Capabilities\ICanCreateResponses;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Module\Response;
|
||||
|
@ -164,6 +163,19 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Module GET method to process submitted data
|
||||
*
|
||||
* Extend this method if the module is supposed to process GET requests.
|
||||
* Doesn't display any content
|
||||
*
|
||||
* @param string[] $request The $_REQUEST content
|
||||
* @return void
|
||||
*/
|
||||
protected function get(array $request = [])
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -210,17 +222,20 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
switch ($this->args->getMethod()) {
|
||||
case Router::DELETE:
|
||||
$this->delete($request);
|
||||
return $this->response->generate();
|
||||
break;
|
||||
case Router::PATCH:
|
||||
$this->patch($request);
|
||||
return $this->response->generate();
|
||||
break;
|
||||
case Router::POST:
|
||||
Core\Hook::callAll($this->args->getModuleName() . '_mod_post', $request);
|
||||
$this->post($request);
|
||||
return $this->response->generate();
|
||||
break;
|
||||
case Router::PUT:
|
||||
$this->put($request);
|
||||
return $this->response->generate();
|
||||
break;
|
||||
case Router::GET:
|
||||
$this->get($request);
|
||||
break;
|
||||
}
|
||||
|
||||
$timestamp = microtime(true);
|
||||
|
@ -245,10 +260,10 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
|
||||
$this->response->setStatus($e->getCode(), $e->getMessage());
|
||||
$this->response->addContent($httpException->content($e));
|
||||
} finally {
|
||||
$this->profiler->set(microtime(true) - $timestamp, 'content');
|
||||
}
|
||||
|
||||
$this->profiler->set(microtime(true) - $timestamp, 'content');
|
||||
|
||||
return $this->response->generate();
|
||||
}
|
||||
|
||||
|
@ -269,7 +284,7 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
$request[$parameter] = $this->getRequestValue($input, $parameter, $defaultvalue);
|
||||
}
|
||||
|
||||
foreach ($input ?? [] as $parameter => $value) {
|
||||
foreach ($input as $parameter => $value) {
|
||||
if ($parameter == 'pagename') {
|
||||
continue;
|
||||
}
|
||||
|
@ -396,8 +411,8 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
public static function checkFormSecurityTokenRedirectOnError(string $err_redirect, string $typename = '', string $formname = 'form_security_token')
|
||||
{
|
||||
if (!self::checkFormSecurityToken($typename, $formname)) {
|
||||
Logger::notice('checkFormSecurityToken failed: user ' . DI::userSession()->getLocalUserNickname() . ' - form element ' . $typename);
|
||||
Logger::debug('checkFormSecurityToken failed', ['request' => $_REQUEST]);
|
||||
DI::logger()->notice('checkFormSecurityToken failed: user ' . DI::userSession()->getLocalUserNickname() . ' - form element ' . $typename);
|
||||
DI::logger()->debug('checkFormSecurityToken failed', ['request' => $_REQUEST]);
|
||||
DI::sysmsg()->addNotice(self::getFormSecurityStandardErrorMessage());
|
||||
DI::baseUrl()->redirect($err_redirect);
|
||||
}
|
||||
|
@ -406,8 +421,8 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
public static function checkFormSecurityTokenForbiddenOnError(string $typename = '', string $formname = 'form_security_token')
|
||||
{
|
||||
if (!self::checkFormSecurityToken($typename, $formname)) {
|
||||
Logger::notice('checkFormSecurityToken failed: user ' . DI::userSession()->getLocalUserNickname() . ' - form element ' . $typename);
|
||||
Logger::debug('checkFormSecurityToken failed', ['request' => $_REQUEST]);
|
||||
DI::logger()->notice('checkFormSecurityToken failed: user ' . DI::userSession()->getLocalUserNickname() . ' - form element ' . $typename);
|
||||
DI::logger()->debug('checkFormSecurityToken failed', ['request' => $_REQUEST]);
|
||||
|
||||
throw new \Friendica\Network\HTTPException\ForbiddenException();
|
||||
}
|
||||
|
@ -456,7 +471,7 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
* @param string $content
|
||||
* @param string $type
|
||||
* @param string|null $content_type
|
||||
* @return void
|
||||
* @return never
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function httpExit(string $content, string $type = Response::TYPE_HTML, ?string $content_type = null)
|
||||
|
@ -493,11 +508,11 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
* @param mixed $content
|
||||
* @param string $content_type
|
||||
* @param int $options A combination of json_encode() binary flags
|
||||
* @return void
|
||||
* @return never
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @see json_encode()
|
||||
*/
|
||||
public function jsonExit($content, string $content_type = 'application/json', int $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
public function jsonExit($content, string $content_type = 'application/json; charset=utf-8', int $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
{
|
||||
$this->httpExit(json_encode($content, $options), ICanCreateResponses::TYPE_JSON, $content_type);
|
||||
}
|
||||
|
@ -508,7 +523,7 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
* @param int $httpCode
|
||||
* @param mixed $content
|
||||
* @param string $content_type
|
||||
* @return void
|
||||
* @return never
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function jsonError(int $httpCode, $content, string $content_type = 'application/json')
|
||||
|
|
|
@ -130,17 +130,33 @@ abstract class BaseRepository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param array $condition
|
||||
* @param array $params
|
||||
* @return BaseEntity
|
||||
* Selects the fields of the first row as array
|
||||
*
|
||||
* @throws NotFoundException
|
||||
*
|
||||
* @return array The resulted fields as array
|
||||
*/
|
||||
final protected function _selectFirstRowAsArray(array $condition, array $params = []): array
|
||||
{
|
||||
$fields = $this->db->selectFirst(static::$table_name, [], $condition, $params);
|
||||
|
||||
if (!$this->db->isResult($fields)) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2025.05 Use `\Friendica\BaseRepository::_selectFirstRowAsArray()` instead
|
||||
*
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
protected function _selectOne(array $condition, array $params = []): BaseEntity
|
||||
{
|
||||
$fields = $this->db->selectFirst(static::$table_name, [], $condition, $params);
|
||||
if (!$this->db->isResult($fields)) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
@trigger_error('`' . __METHOD__ . '()` is deprecated since 2025.05 and will be removed after 5 months, use `\Friendica\BaseRepository::_selectFirstRowAsArray()` instead.', E_USER_DEPRECATED);
|
||||
|
||||
$fields = $this->_selectFirstRowAsArray( $condition, $params);
|
||||
|
||||
return $this->factory->createFromTableRow($fields);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
namespace Friendica\Collection\Api\Mastodon;
|
||||
|
||||
use Friendica\Api\Entity\Mastodon\Field;
|
||||
use Friendica\BaseCollection;
|
||||
use Friendica\Object\Api\Mastodon\Field;
|
||||
|
||||
class Fields extends BaseCollection
|
||||
{
|
||||
|
|
|
@ -8,10 +8,9 @@
|
|||
namespace Friendica\Console;
|
||||
|
||||
use Console_Table;
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Pager;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Addon as AddonCore;
|
||||
use Friendica\Core\Addon\AddonHelper;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Util\Strings;
|
||||
use RuntimeException;
|
||||
|
@ -24,7 +23,7 @@ class Addon extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
|
@ -35,6 +34,7 @@ class Addon extends \Asika\SimpleConsole\Console
|
|||
* @var Database
|
||||
*/
|
||||
private $dba;
|
||||
private AddonHelper $addonHelper;
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
|
@ -57,15 +57,16 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, L10n $l10n, Database $dba, array $argv = null)
|
||||
public function __construct(Mode $appMode, L10n $l10n, Database $dba, AddonHelper $addonHelper, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->appMode = $appMode;
|
||||
$this->l10n = $l10n;
|
||||
$this->dba = $dba;
|
||||
$this->addonHelper = $addonHelper;
|
||||
|
||||
AddonCore::loadAddons();
|
||||
$this->addonHelper->loadAddons();
|
||||
}
|
||||
|
||||
protected function doExecute(): int
|
||||
|
@ -122,28 +123,30 @@ HELP;
|
|||
$this->out($this->getHelp());
|
||||
return false;
|
||||
}
|
||||
foreach (AddonCore::getAvailableList() as $addon) {
|
||||
$addon_name = $addon[0];
|
||||
$enabled = AddonCore::isEnabled($addon_name) ? "enabled" : "disabled";
|
||||
switch ($subCmd) {
|
||||
case 'all':
|
||||
$table->addRow([$addon_name, $enabled]);
|
||||
break;
|
||||
case 'enabled':
|
||||
if (!$enabled) {
|
||||
continue 2;
|
||||
}
|
||||
$table->addRow([$addon_name]);
|
||||
case 'disabled':
|
||||
if ($enabled) {
|
||||
continue 2;
|
||||
}
|
||||
$table->addRow([$addon_name]);
|
||||
break;
|
||||
|
||||
foreach ($this->addonHelper->getAvailableAddons() as $addonId) {
|
||||
$enabled = $this->addonHelper->isAddonEnabled($addonId);
|
||||
|
||||
if ($subCmd === 'all') {
|
||||
$table->addRow([$addonId, $enabled ? 'enabled' : 'disabled']);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($subCmd === 'enabled' && $enabled === true) {
|
||||
$table->addRow([$addonId]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($subCmd === 'disabled' && $enabled === false) {
|
||||
$table->addRow([$addonId]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->out($table->getTable());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,11 +164,11 @@ HELP;
|
|||
throw new RuntimeException($this->l10n->t('Addon not found'));
|
||||
}
|
||||
|
||||
if (AddonCore::isEnabled($addon)) {
|
||||
if ($this->addonHelper->isAddonEnabled($addon)) {
|
||||
throw new RuntimeException($this->l10n->t('Addon already enabled'));
|
||||
}
|
||||
|
||||
AddonCore::install($addon);
|
||||
$this->addonHelper->installAddon($addon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -185,11 +188,11 @@ HELP;
|
|||
throw new RuntimeException($this->l10n->t('Addon not found'));
|
||||
}
|
||||
|
||||
if (!AddonCore::isEnabled($addon)) {
|
||||
if (!$this->addonHelper->isAddonEnabled($addon)) {
|
||||
throw new RuntimeException($this->l10n->t('Addon already disabled'));
|
||||
}
|
||||
|
||||
AddonCore::uninstall($addon);
|
||||
$this->addonHelper->uninstallAddon($addon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
|
@ -28,7 +28,7 @@ class ArchiveContact extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
|
@ -57,7 +57,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, Database $dba, \Friendica\Core\L10n $l10n, array $argv = null)
|
||||
public function __construct(Mode $appMode, Database $dba, \Friendica\Core\L10n $l10n, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
namespace Friendica\Console;
|
||||
|
||||
use Asika\SimpleConsole\Console;
|
||||
use Friendica\App;
|
||||
use Friendica\App\BaseURL;
|
||||
use Exception;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Config\ValueObject\Cache;
|
||||
use Friendica\Core\Installer;
|
||||
|
@ -20,7 +20,7 @@ use RuntimeException;
|
|||
|
||||
class AutomaticInstallation extends Console
|
||||
{
|
||||
/** @var App\Mode */
|
||||
/** @var Mode */
|
||||
private $appMode;
|
||||
/** @var \Friendica\Core\Config\ValueObject\Cache */
|
||||
private $configCache;
|
||||
|
@ -86,7 +86,7 @@ Examples
|
|||
HELP;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, Cache $configCache, IManageConfigValues $config, Database $dba, array $argv = null)
|
||||
public function __construct(Mode $appMode, Cache $configCache, IManageConfigValues $config, Database $dba, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Friendica\Console;
|
||||
|
||||
use Asika\SimpleConsole\CommandArgsException;
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Cache\Enum\Duration;
|
||||
use Friendica\Core\Cache\Capability\ICanCache;
|
||||
use RuntimeException;
|
||||
|
@ -25,7 +25,7 @@ class Cache extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
|
||||
|
@ -68,7 +68,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, ICanCache $cache, array $argv = null)
|
||||
public function __construct(Mode $appMode, ICanCache $cache, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
@ -85,7 +85,7 @@ HELP;
|
|||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (!$this->appMode->has(App\Mode::DBAVAILABLE)) {
|
||||
if (!$this->appMode->has(Mode::DBAVAILABLE)) {
|
||||
$this->out('Database isn\'t ready or populated yet, database cache won\'t be available');
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Friendica\Console;
|
|||
use Friendica\App\BaseURL;
|
||||
use Friendica\Contact\Avatar;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
|
||||
|
@ -21,12 +22,12 @@ class ClearAvatarCache extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var $dba Friendica\Database\Database
|
||||
* @var Database
|
||||
*/
|
||||
private $dba;
|
||||
|
||||
/**
|
||||
* @var $baseurl Friendica\App\BaseURL
|
||||
* @var BaseURL
|
||||
*/
|
||||
private $baseUrl;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Friendica\Console;
|
||||
|
||||
use Asika\SimpleConsole\CommandArgsException;
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use RuntimeException;
|
||||
|
||||
|
@ -38,7 +38,7 @@ class Config extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
|
@ -80,7 +80,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, IManageConfigValues $config, array $argv = null)
|
||||
public function __construct(Mode $appMode, IManageConfigValues $config, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
namespace Friendica\Console;
|
||||
|
||||
use Console_Table;
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact as ContactModel;
|
||||
use Friendica\Model\User as UserModel;
|
||||
|
@ -25,11 +26,11 @@ class Contact extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
* @var IPConfig
|
||||
* @var IManagePersonalConfigValues
|
||||
*/
|
||||
private $pConfig;
|
||||
|
||||
|
@ -55,7 +56,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, array $argv = null)
|
||||
public function __construct(Mode $appMode, ?array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
@ -83,13 +84,13 @@ HELP;
|
|||
|
||||
switch ($command) {
|
||||
case 'add':
|
||||
return $this->addContact();
|
||||
return ($this->addContact()) ? 0 : 1;
|
||||
case 'remove':
|
||||
return $this->removeContact();
|
||||
return ($this->removeContact()) ? 0 : 1;
|
||||
case 'search':
|
||||
return $this->searchContact();
|
||||
return ($this->searchContact()) ? 0 : 1;
|
||||
case 'terminate':
|
||||
return $this->terminateContact();
|
||||
return ($this->terminateContact()) ? 0 : 1;
|
||||
default:
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.');
|
||||
}
|
||||
|
@ -158,9 +159,10 @@ HELP;
|
|||
|
||||
if ($result['success']) {
|
||||
$this->out('User ' . $user['nickname'] . ' now connected to ' . $url . ', contact ID ' . $result['cid']);
|
||||
} else {
|
||||
throw new RuntimeException($result['message']);
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new RuntimeException($result['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,7 +206,7 @@ HELP;
|
|||
/**
|
||||
* Marks a contact for removal
|
||||
*/
|
||||
private function removeContact()
|
||||
private function removeContact(): bool
|
||||
{
|
||||
$cid = $this->getArgument(1);
|
||||
if (empty($cid)) {
|
||||
|
@ -216,6 +218,8 @@ HELP;
|
|||
}
|
||||
|
||||
ContactModel::remove($cid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
224
src/Console/Daemon.php
Normal file
224
src/Console/Daemon.php
Normal file
|
@ -0,0 +1,224 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Asika\SimpleConsole\CommandArgsException;
|
||||
use Asika\SimpleConsole\Console;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Update;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\System\Daemon as SysDaemon;
|
||||
use Friendica\Util\BasePath;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Console command for interacting with the daemon
|
||||
*/
|
||||
final class Daemon extends Console
|
||||
{
|
||||
private Mode $mode;
|
||||
private IManageConfigValues $config;
|
||||
private IManageKeyValuePairs $keyValue;
|
||||
private BasePath $basePath;
|
||||
private System $system;
|
||||
private LoggerInterface $logger;
|
||||
private Database $dba;
|
||||
private SysDaemon $daemon;
|
||||
|
||||
/**
|
||||
* @param Mode $mode
|
||||
* @param IManageConfigValues $config
|
||||
* @param IManageKeyValuePairs $keyValue
|
||||
* @param BasePath $basePath
|
||||
* @param System $system
|
||||
* @param LoggerInterface $logger
|
||||
* @param Database $dba
|
||||
* @param SysDaemon $daemon
|
||||
* @param array|null $argv
|
||||
*/
|
||||
public function __construct(Mode $mode, IManageConfigValues $config, IManageKeyValuePairs $keyValue, BasePath $basePath, System $system, LoggerInterface $logger, Database $dba, SysDaemon $daemon, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->config = $config;
|
||||
$this->keyValue = $keyValue;
|
||||
$this->basePath = $basePath;
|
||||
$this->system = $system;
|
||||
$this->logger = $logger;
|
||||
$this->dba = $dba;
|
||||
$this->daemon = $daemon;
|
||||
}
|
||||
|
||||
protected function getHelp(): string
|
||||
{
|
||||
return <<<HELP
|
||||
Daemon - Interact with the Friendica daemon
|
||||
Synopsis
|
||||
bin/console daemon start [-h|--help|-?] [-v] [-f]
|
||||
bin/console daemon stop [-h|--help|-?] [-v]
|
||||
bin/console daemon status [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
Interact with the Friendica daemon
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
-f|--foreground Runs the daemon in the foreground
|
||||
|
||||
Examples
|
||||
bin/console daemon start -f
|
||||
Starts the daemon in the foreground
|
||||
|
||||
bin/console daemon status
|
||||
Gets the status of the daemon
|
||||
HELP;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->mode->isInstall()) {
|
||||
throw new RuntimeException("Friendica isn't properly installed yet");
|
||||
}
|
||||
|
||||
$this->mode->setExecutor(Mode::DAEMON);
|
||||
|
||||
$this->config->reload();
|
||||
|
||||
if (empty($this->config->get('system', 'pidfile'))) {
|
||||
throw new RuntimeException(
|
||||
<<< TXT
|
||||
Please set system.pidfile in config/local.config.php. For example:
|
||||
|
||||
'system' => [
|
||||
'pidfile' => '/path/to/daemon.pid',
|
||||
],
|
||||
TXT
|
||||
);
|
||||
}
|
||||
|
||||
$pidfile = $this->config->get('system', 'pidfile');
|
||||
|
||||
$daemonMode = $this->getArgument(0);
|
||||
$foreground = $this->getOption(['f', 'foreground']) ?? false;
|
||||
|
||||
if (empty($daemonMode)) {
|
||||
throw new CommandArgsException("Please use either 'start', 'stop' or 'status'");
|
||||
}
|
||||
|
||||
$this->daemon->init($pidfile);
|
||||
|
||||
if ($daemonMode == 'status') {
|
||||
if ($this->daemon->isRunning()) {
|
||||
$this->out(sprintf("Daemon process %s is running (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
} else {
|
||||
$this->out(sprintf("Daemon process %s isn't running (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($daemonMode == 'stop') {
|
||||
if (!$this->daemon->isRunning()) {
|
||||
$this->out(sprintf("Daemon process %s isn't running (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($this->daemon->stop()) {
|
||||
$this->keyValue->set('worker_daemon_mode', false);
|
||||
$this->out(sprintf("Daemon process %s was killed (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($this->daemon->isRunning()) {
|
||||
$this->out(sprintf("Daemon process %s is already running (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($daemonMode == "start") {
|
||||
$this->out("Starting Friendica daemon");
|
||||
|
||||
$this->daemon->start(function () {
|
||||
$wait_interval = intval($this->config->get('system', 'cron_interval', 5)) * 60;
|
||||
|
||||
$do_cron = true;
|
||||
$last_cron = 0;
|
||||
|
||||
$path = $this->basePath->getPath();
|
||||
|
||||
// Now running as a daemon.
|
||||
while (true) {
|
||||
// Check the database structure and possibly fixes it
|
||||
Update::check($path, true);
|
||||
|
||||
if (!$do_cron && ($last_cron + $wait_interval) < time()) {
|
||||
$this->logger->info('Forcing cron worker call.', ['pid' => $this->daemon->getPid()]);
|
||||
$do_cron = true;
|
||||
}
|
||||
|
||||
if ($do_cron || (!$this->system->isMaxLoadReached() && Worker::entriesExists() && Worker::isReady())) {
|
||||
Worker::spawnWorker($do_cron);
|
||||
} else {
|
||||
$this->logger->info('Cool down for 5 seconds', ['pid' => $this->daemon->getPid()]);
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
if ($do_cron) {
|
||||
// We force a reconnect of the database connection.
|
||||
// This is done to ensure that the connection don't get lost over time.
|
||||
$this->dba->reconnect();
|
||||
|
||||
$last_cron = time();
|
||||
}
|
||||
|
||||
$start = time();
|
||||
$this->logger->info('Sleeping', ['pid' => $this->daemon->getPid(), 'until' => gmdate(DateTimeFormat::MYSQL, $start + $wait_interval)]);
|
||||
|
||||
do {
|
||||
$seconds = (time() - $start);
|
||||
|
||||
// logarithmic wait time calculation.
|
||||
// Background: After jobs had been started, they often fork many workers.
|
||||
// To not waste too much time, the sleep period increases.
|
||||
$arg = (($seconds + 1) / ($wait_interval / 9)) + 1;
|
||||
$sleep = min(1000000, round(log10($arg) * 1000000, 0));
|
||||
|
||||
$this->daemon->sleep((int)$sleep);
|
||||
|
||||
$timeout = ($seconds >= $wait_interval);
|
||||
} while (!$timeout && !Worker\IPC::JobsExists());
|
||||
|
||||
if ($timeout) {
|
||||
$do_cron = true;
|
||||
$this->logger->info('Woke up after $wait_interval seconds.', ['pid' => $this->daemon->getPid(), 'sleep' => $wait_interval]);
|
||||
} else {
|
||||
$do_cron = false;
|
||||
$this->logger->info('Worker jobs are calling to be forked.', ['pid' => $this->daemon->getPid()]);
|
||||
}
|
||||
}
|
||||
}, $foreground);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->err('Invalid command');
|
||||
$this->out($this->getHelp());
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\AppHelper;
|
||||
|
||||
/**
|
||||
* When I installed docblox, I had the experience that it does not generate any output at all.
|
||||
|
@ -33,14 +33,14 @@ class DocBloxErrorChecker extends \Asika\SimpleConsole\Console
|
|||
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/** @var App */
|
||||
private $app;
|
||||
/** @var string */
|
||||
private $basePath;
|
||||
|
||||
public function __construct(App $app, array $argv = null)
|
||||
public function __construct(AppHelper $appHelper, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->app = $app;
|
||||
$this->basePath = $appHelper->getBasePath();
|
||||
}
|
||||
|
||||
protected function getHelp()
|
||||
|
@ -73,7 +73,7 @@ HELP;
|
|||
throw new \RuntimeException('DocBlox isn\'t available.');
|
||||
}
|
||||
|
||||
$dir = $this->app->getBasePath();
|
||||
$dir = $this->basePath;
|
||||
|
||||
//stack for dirs to search
|
||||
$dirstack = [];
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\App;
|
||||
use Asika\SimpleConsole\CommandArgsException;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Util\Strings;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
|
@ -23,13 +22,17 @@ class FixAPDeliveryWorkerTaskParameters extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
* @var Database
|
||||
*/
|
||||
private $dba;
|
||||
/**
|
||||
* @var L10n
|
||||
*/
|
||||
private $l10n;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
@ -62,7 +65,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, Database $dba, \Friendica\Core\L10n $l10n, array $argv = null)
|
||||
public function __construct(Mode $appMode, Database $dba, L10n $l10n, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
@ -80,7 +83,7 @@ HELP;
|
|||
}
|
||||
|
||||
if (count($this->args) > 0) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
throw new CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
if ($this->appMode->isInstall()) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Model\Contact;
|
||||
|
||||
|
@ -22,7 +22,7 @@ class GlobalCommunityBlock extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
|
@ -48,7 +48,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, L10n $l10n, $argv = null)
|
||||
public function __construct(Mode $appMode, L10n $l10n, $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
|
161
src/Console/JetstreamDaemon.php
Normal file
161
src/Console/JetstreamDaemon.php
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2025, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Asika\SimpleConsole\Console;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Addon\AddonHelper;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
|
||||
use Friendica\Protocol\ATProtocol\Jetstream;
|
||||
use Friendica\System\Daemon as SysDaemon;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Console command for interacting with the daemon
|
||||
*/
|
||||
final class JetstreamDaemon extends Console
|
||||
{
|
||||
private Mode $mode;
|
||||
private IManageConfigValues $config;
|
||||
private IManageKeyValuePairs $keyValue;
|
||||
private SysDaemon $daemon;
|
||||
private Jetstream $jetstream;
|
||||
private AddonHelper $addonHelper;
|
||||
|
||||
/**
|
||||
* @param Mode $mode
|
||||
* @param IManageConfigValues $config
|
||||
* @param IManageKeyValuePairs $keyValue
|
||||
* @param SysDaemon $daemon
|
||||
* @param Jetstream $jetstream
|
||||
* @param array|null $argv
|
||||
*/
|
||||
public function __construct(Mode $mode, IManageConfigValues $config, IManageKeyValuePairs $keyValue, SysDaemon $daemon, Jetstream $jetstream, AddonHelper $addonHelper, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->config = $config;
|
||||
$this->keyValue = $keyValue;
|
||||
$this->jetstream = $jetstream;
|
||||
$this->daemon = $daemon;
|
||||
$this->addonHelper = $addonHelper;
|
||||
}
|
||||
|
||||
protected function getHelp(): string
|
||||
{
|
||||
return <<<HELP
|
||||
jetstream - Interact with the Jetstream daemon
|
||||
Synopsis
|
||||
bin/console jetstream start [-h|--help|-?] [-v] [-f]
|
||||
bin/console jetstream stop [-h|--help|-?] [-v]
|
||||
bin/console jetstream status [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
Interact with the Jetstream daemon
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
-f|--foreground Runs the daemon in the foreground
|
||||
|
||||
Examples
|
||||
bin/console jetstream start -f
|
||||
Starts the daemon in the foreground
|
||||
|
||||
bin/console jetstream status
|
||||
Gets the status of the daemon
|
||||
HELP;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
if ($this->mode->isInstall()) {
|
||||
throw new RuntimeException("Friendica isn't properly installed yet");
|
||||
}
|
||||
|
||||
$this->config->reload();
|
||||
|
||||
if (empty($this->config->get('jetstream', 'pidfile'))) {
|
||||
throw new RuntimeException(
|
||||
<<< TXT
|
||||
Please set jetstream.pidfile in config/local.config.php. For example:
|
||||
|
||||
'jetstream' => [
|
||||
'pidfile' => '/path/to/jetstream.pid',
|
||||
],
|
||||
TXT
|
||||
);
|
||||
}
|
||||
|
||||
$this->addonHelper->loadAddons();
|
||||
Hook::loadHooks();
|
||||
|
||||
if (!$this->addonHelper->isAddonEnabled('bluesky')) {
|
||||
throw new RuntimeException("Bluesky has to be enabled.\n");
|
||||
}
|
||||
|
||||
$pidfile = $this->config->get('jetstream', 'pidfile');
|
||||
|
||||
$daemonMode = $this->getArgument(0);
|
||||
$foreground = $this->getOption(['f', 'foreground']) ?? false;
|
||||
|
||||
if (empty($daemonMode)) {
|
||||
throw new RuntimeException("Please use either 'start', 'stop' or 'status'");
|
||||
}
|
||||
|
||||
$this->daemon->init($pidfile);
|
||||
|
||||
if ($daemonMode == 'status') {
|
||||
if ($this->daemon->isRunning()) {
|
||||
$this->out(sprintf("Daemon process %s is running (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
} else {
|
||||
$this->out(sprintf("Daemon process %s isn't running (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($daemonMode == 'stop') {
|
||||
if (!$this->daemon->isRunning()) {
|
||||
$this->out(sprintf("Daemon process %s isn't running (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($this->daemon->stop()) {
|
||||
$this->keyValue->set('worker_daemon_mode', false);
|
||||
$this->out(sprintf("Daemon process %s was killed (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($this->daemon->isRunning()) {
|
||||
$this->out(sprintf("Daemon process %s is already running (%s)", $this->daemon->getPid(), $this->daemon->getPidfile()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($daemonMode == "start") {
|
||||
$this->out("Starting Jetstream daemon");
|
||||
|
||||
$this->daemon->start(function () {
|
||||
$this->jetstream->listen();
|
||||
}, $foreground);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->err('Invalid command');
|
||||
$this->out($this->getHelp());
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
namespace Friendica\Console;
|
||||
|
||||
use Asika\SimpleConsole\CommandArgsException;
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use RuntimeException;
|
||||
|
||||
|
@ -23,7 +23,7 @@ class Lock extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
|
||||
|
@ -62,7 +62,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, ICanLock $lock, array $argv = null)
|
||||
public function __construct(Mode $appMode, ICanLock $lock, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
@ -79,7 +79,7 @@ HELP;
|
|||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (!$this->appMode->has(App\Mode::DBAVAILABLE)) {
|
||||
if (!$this->appMode->has(Mode::DBAVAILABLE)) {
|
||||
$this->out('Database isn\'t ready or populated yet, database cache won\'t be available');
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,7 @@ class Maintenance extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
|
@ -55,7 +55,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, IManageConfigValues $config, $argv = null)
|
||||
public function __construct(Mode $appMode, IManageConfigValues $config, $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class MergeContacts extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var $dba Database
|
||||
* @var Database
|
||||
*/
|
||||
private $dba;
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ namespace Friendica\Console;
|
|||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\Contact\Avatar;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Protocol;
|
||||
|
||||
/**
|
||||
* tool to move cached avatars to the avatar file cache.
|
||||
|
@ -25,12 +25,12 @@ class MoveToAvatarCache extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var $dba Friendica\Database\Database
|
||||
* @var Database
|
||||
*/
|
||||
private $dba;
|
||||
|
||||
/**
|
||||
* @var $baseurl Friendica\App\BaseURL
|
||||
* @var BaseURL
|
||||
*/
|
||||
private $baseUrl;
|
||||
|
||||
|
@ -115,6 +115,10 @@ HELP;
|
|||
|
||||
private function storeAvatar(string $resourceid, array $contact, bool $quit_on_invalid)
|
||||
{
|
||||
$photo = false;
|
||||
$imgdata = false;
|
||||
$image = null;
|
||||
|
||||
$valid = !empty($resourceid);
|
||||
if ($valid) {
|
||||
$this->out('1', false);
|
||||
|
@ -143,7 +147,7 @@ HELP;
|
|||
}
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
if ($valid && $image instanceof Image) {
|
||||
$this->out('4', false);
|
||||
$fields = Avatar::storeAvatarByImage($contact, $image);
|
||||
} else {
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\AppHelper;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Read a strings.php file and create messages.po in the same directory
|
||||
|
@ -20,14 +21,14 @@ class PhpToPo extends \Asika\SimpleConsole\Console
|
|||
private $normBaseMsgIds = [];
|
||||
const NORM_REGEXP = "|[\\\]|";
|
||||
|
||||
/** @var App */
|
||||
private $app;
|
||||
/** @var AppHelper */
|
||||
private $appHelper;
|
||||
|
||||
public function __construct(App $app, array $argv = null)
|
||||
public function __construct(AppHelper $appHelper, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->app = $app;
|
||||
$this->appHelper = $appHelper;
|
||||
}
|
||||
|
||||
protected function getHelp()
|
||||
|
@ -66,7 +67,8 @@ HELP;
|
|||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
$a = $this->app;
|
||||
$a = new stdClass();
|
||||
$a->strings = [];
|
||||
|
||||
$phpfile = realpath($this->getArgument(0));
|
||||
|
||||
|
|
|
@ -175,11 +175,11 @@ HELP;
|
|||
* @param string $string
|
||||
* @param array|string $node
|
||||
*/
|
||||
private static function parse(string $string, &$node = [])
|
||||
private static function parse(string $string, &$node)
|
||||
{
|
||||
// Removes extra outward parentheses
|
||||
if (strpos($string, '(') === 0 && strrpos($string, ')') === strlen($string) - 1) {
|
||||
$string = substr($string, 1, -1);
|
||||
$string = (string) substr($string, 1, -1);
|
||||
}
|
||||
|
||||
$q = strpos($string, '?');
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Update;
|
||||
use Friendica\DI;
|
||||
|
||||
/**
|
||||
* Performs database post updates
|
||||
|
@ -20,7 +21,7 @@ class PostUpdate extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
|
@ -31,6 +32,10 @@ class PostUpdate extends \Asika\SimpleConsole\Console
|
|||
* @var L10n
|
||||
*/
|
||||
private $l10n;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $basePath;
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
|
@ -46,19 +51,18 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, IManageKeyValuePairs $keyValue, L10n $l10n, array $argv = null)
|
||||
public function __construct(Mode $appMode, IManageKeyValuePairs $keyValue, L10n $l10n, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->appMode = $appMode;
|
||||
$this->keyValue = $keyValue;
|
||||
$this->l10n = $l10n;
|
||||
$this->basePath = DI::appHelper()->getBasePath();
|
||||
}
|
||||
|
||||
protected function doExecute(): int
|
||||
{
|
||||
$a = \Friendica\DI::app();
|
||||
|
||||
if ($this->getOption($this->helpOptions)) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
|
@ -79,7 +83,7 @@ HELP;
|
|||
}
|
||||
|
||||
echo $this->l10n->t('Check for pending update actions.') . "\n";
|
||||
Update::run($a->getBasePath(), true, false, true, false);
|
||||
Update::run($this->basePath, true, false, true, false);
|
||||
echo $this->l10n->t('Done.') . "\n";
|
||||
|
||||
echo $this->l10n->t('Execute pending post updates.') . "\n";
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Friendica\Console;
|
||||
|
||||
use Asika\SimpleConsole\CommandArgsException;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\APContact;
|
||||
use Friendica\Protocol\ActivityPub\Transmitter;
|
||||
use Friendica\Protocol\Relay as ProtocolRelay;
|
||||
|
@ -23,7 +24,7 @@ class Relay extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var $dba Friendica\Database\Database
|
||||
* @var Database
|
||||
*/
|
||||
private $dba;
|
||||
|
||||
|
|
|
@ -192,5 +192,7 @@ HELP;
|
|||
} while ($moved);
|
||||
|
||||
$this->out(sprintf(date('[Y-m-d H:i:s] ') . 'Moved %d files total', $total));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Friendica\Console;
|
||||
|
||||
use Console_Table;
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Content\Pager;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
|
@ -26,7 +26,7 @@ class User extends \Asika\SimpleConsole\Console
|
|||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var App\Mode
|
||||
* @var Mode
|
||||
*/
|
||||
private $appMode;
|
||||
/**
|
||||
|
@ -74,7 +74,7 @@ HELP;
|
|||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(App\Mode $appMode, L10n $l10n, IManagePersonalConfigValues $pConfig, array $argv = null)
|
||||
public function __construct(Mode $appMode, L10n $l10n, IManagePersonalConfigValues $pConfig, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
|
@ -106,23 +106,23 @@ HELP;
|
|||
case 'password':
|
||||
return $this->password();
|
||||
case 'add':
|
||||
return $this->addUser();
|
||||
return ($this->addUser()) ? 0 : 1;
|
||||
case 'allow':
|
||||
return $this->pendingUser(true);
|
||||
return ($this->pendingUser(true)) ? 0 : 1;
|
||||
case 'deny':
|
||||
return $this->pendingUser(false);
|
||||
return ($this->pendingUser(false)) ? 0 : 1;
|
||||
case 'block':
|
||||
return $this->blockUser(true);
|
||||
return ($this->blockUser(true)) ? 0 : 1;
|
||||
case 'unblock':
|
||||
return $this->blockUser(false);
|
||||
return ($this->blockUser(false)) ? 0 : 1;
|
||||
case 'delete':
|
||||
return $this->deleteUser();
|
||||
return ($this->deleteUser()) ? 0 : 1;
|
||||
case 'list':
|
||||
return $this->listUser();
|
||||
return ($this->listUser()) ? 0 : 1;
|
||||
case 'search':
|
||||
return $this->searchUser();
|
||||
return ($this->searchUser()) ? 0 : 1;
|
||||
case 'config':
|
||||
return $this->configUser();
|
||||
return ($this->configUser()) ? 0 : 1;
|
||||
default:
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.');
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ HELP;
|
|||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function password()
|
||||
private function password(): int
|
||||
{
|
||||
$user = $this->getUserByNick(1);
|
||||
|
||||
|
@ -212,7 +212,7 @@ HELP;
|
|||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private function addUser()
|
||||
private function addUser(): bool
|
||||
{
|
||||
$name = $this->getArgument(1);
|
||||
$nick = $this->getArgument(2);
|
||||
|
@ -512,5 +512,7 @@ HELP;
|
|||
$this->out($this->getHelp());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
96
src/Console/Worker.php
Normal file
96
src/Console/Worker.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Console;
|
||||
|
||||
use Asika\SimpleConsole\Console;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Core\Update;
|
||||
use Friendica\Core\Worker as CoreWorker;
|
||||
use Friendica\Core\Worker\Repository\Process as ProcessRepository;
|
||||
use Friendica\Util\BasePath;
|
||||
|
||||
/**
|
||||
* Console command for starting worker
|
||||
*/
|
||||
final class Worker extends Console
|
||||
{
|
||||
private Mode $mode;
|
||||
private BasePath $basePath;
|
||||
private ProcessRepository $processRepo;
|
||||
|
||||
/**
|
||||
* @param Mode $mode
|
||||
* @param BasePath $basePath
|
||||
* @param ProcessRepository $processRepo
|
||||
* @param array|null $argv
|
||||
*/
|
||||
public function __construct(Mode $mode, BasePath $basePath, ProcessRepository $processRepo, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->basePath = $basePath;
|
||||
$this->processRepo = $processRepo;
|
||||
}
|
||||
|
||||
protected function getHelp(): string
|
||||
{
|
||||
return <<<HELP
|
||||
Worker - Start a worker
|
||||
Synopsis
|
||||
bin/console worker [-h|--help|-?] [-v] [-n|--no_cron] [-s|--spawn]
|
||||
|
||||
Description
|
||||
Start a worker process
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
-n|--no_cron Don't executes the Cronjob
|
||||
-s|--spawn Spawn an additional worker
|
||||
|
||||
Examples
|
||||
bin/console worker -n
|
||||
Starts the worker without executing other recurring tasks
|
||||
|
||||
bin/console worker -s
|
||||
Starts the worker and immediately spawn another worker process
|
||||
HELP;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
$this->mode->setExecutor(Mode::WORKER);
|
||||
|
||||
// Check the database structure and possibly fixes it
|
||||
Update::check($this->basePath->getPath(), true);
|
||||
|
||||
// Quit when in maintenance
|
||||
if (!$this->mode->has(Mode::MAINTENANCEDISABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$spawn = $this->getOption(['s', 'spawn'], false);
|
||||
|
||||
if ($spawn) {
|
||||
CoreWorker::spawnWorker();
|
||||
exit();
|
||||
}
|
||||
|
||||
$run_cron = !$this->getOption(['n', 'no_cron'], false);
|
||||
|
||||
$process = $this->processRepo->create(getmypid(), 'worker.php');
|
||||
|
||||
CoreWorker::processQueue($run_cron, $process);
|
||||
CoreWorker::unclaimProcess($process);
|
||||
|
||||
$this->processRepo->delete($process);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Friendica\Contact;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\DI;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
|
@ -47,36 +46,36 @@ class Avatar
|
|||
|
||||
if (($avatar != $contact['avatar']) || $force) {
|
||||
self::deleteCache($contact);
|
||||
Logger::debug('Avatar file name changed', ['new' => $avatar, 'old' => $contact['avatar']]);
|
||||
DI::logger()->debug('Avatar file name changed', ['new' => $avatar, 'old' => $contact['avatar']]);
|
||||
} elseif (self::isCacheFile($contact['photo']) && self::isCacheFile($contact['thumb']) && self::isCacheFile($contact['micro'])) {
|
||||
$fields['photo'] = $contact['photo'];
|
||||
$fields['thumb'] = $contact['thumb'];
|
||||
$fields['micro'] = $contact['micro'];
|
||||
Logger::debug('Using existing cache files', ['uri-id' => $contact['uri-id'], 'fields' => $fields]);
|
||||
DI::logger()->debug('Using existing cache files', ['uri-id' => $contact['uri-id'], 'fields' => $fields]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
try {
|
||||
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
||||
} catch (\Exception $exception) {
|
||||
Logger::notice('Avatar is invalid', ['avatar' => $avatar, 'exception' => $exception]);
|
||||
DI::logger()->notice('Avatar is invalid', ['avatar' => $avatar, 'exception' => $exception]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
if (!$fetchResult->isSuccess()) {
|
||||
Logger::debug('Fetching was unsuccessful', ['avatar' => $avatar]);
|
||||
DI::logger()->debug('Fetching was unsuccessful', ['avatar' => $avatar]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$img_str = $fetchResult->getBodyString();
|
||||
if (empty($img_str)) {
|
||||
Logger::debug('Avatar is invalid', ['avatar' => $avatar]);
|
||||
DI::logger()->debug('Avatar is invalid', ['avatar' => $avatar]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$image = new Image($img_str, $fetchResult->getContentType(), $avatar);
|
||||
if (!$image->isValid()) {
|
||||
Logger::debug('Avatar picture is invalid', ['avatar' => $avatar]);
|
||||
DI::logger()->debug('Avatar picture is invalid', ['avatar' => $avatar]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
@ -89,7 +88,7 @@ class Avatar
|
|||
$fields['thumb'] = self::storeAvatarCache($image, $filename, Proxy::PIXEL_THUMB, $timestamp);
|
||||
$fields['micro'] = self::storeAvatarCache($image, $filename, Proxy::PIXEL_MICRO, $timestamp);
|
||||
|
||||
Logger::debug('Storing new avatar cache', ['uri-id' => $contact['uri-id'], 'fields' => $fields]);
|
||||
DI::logger()->debug('Storing new avatar cache', ['uri-id' => $contact['uri-id'], 'fields' => $fields]);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
@ -155,36 +154,36 @@ class Avatar
|
|||
|
||||
if (!file_exists($dirpath)) {
|
||||
if (!@mkdir($dirpath, $dir_perm) && !file_exists($dirpath)) {
|
||||
Logger::warning('Directory could not be created', ['directory' => $dirpath]);
|
||||
DI::logger()->warning('Directory could not be created', ['directory' => $dirpath]);
|
||||
}
|
||||
} elseif ((($old_perm = fileperms($dirpath) & 0777) != $dir_perm) && !chmod($dirpath, $dir_perm)) {
|
||||
Logger::warning('Directory permissions could not be changed', ['directory' => $dirpath, 'old' => $old_perm, 'new' => $dir_perm]);
|
||||
DI::logger()->warning('Directory permissions could not be changed', ['directory' => $dirpath, 'old' => $old_perm, 'new' => $dir_perm]);
|
||||
}
|
||||
|
||||
if ((($old_group = filegroup($dirpath)) != $group) && !chgrp($dirpath, $group)) {
|
||||
Logger::warning('Directory group could not be changed', ['directory' => $dirpath, 'old' => $old_group, 'new' => $group]);
|
||||
DI::logger()->warning('Directory group could not be changed', ['directory' => $dirpath, 'old' => $old_group, 'new' => $group]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_put_contents($filepath, $image->asString())) {
|
||||
Logger::warning('File could not be created', ['file' => $filepath]);
|
||||
DI::logger()->warning('File could not be created', ['file' => $filepath]);
|
||||
}
|
||||
|
||||
$old_perm = fileperms($filepath) & 0666;
|
||||
$old_group = filegroup($filepath);
|
||||
|
||||
if (($old_perm != $file_perm) && !chmod($filepath, $file_perm)) {
|
||||
Logger::warning('File permissions could not be changed', ['file' => $filepath, 'old' => $old_perm, 'new' => $file_perm]);
|
||||
DI::logger()->warning('File permissions could not be changed', ['file' => $filepath, 'old' => $old_perm, 'new' => $file_perm]);
|
||||
}
|
||||
|
||||
if (($old_group != $group) && !chgrp($filepath, $group)) {
|
||||
Logger::warning('File group could not be changed', ['file' => $filepath, 'old' => $old_group, 'new' => $group]);
|
||||
DI::logger()->warning('File group could not be changed', ['file' => $filepath, 'old' => $old_group, 'new' => $group]);
|
||||
}
|
||||
|
||||
DI::profiler()->stopRecording();
|
||||
|
||||
if (!file_exists($filepath)) {
|
||||
Logger::warning('Avatar cache file could not be stored', ['file' => $filepath]);
|
||||
DI::logger()->warning('Avatar cache file could not be stored', ['file' => $filepath]);
|
||||
return '';
|
||||
}
|
||||
|
||||
|
@ -235,9 +234,6 @@ class Avatar
|
|||
|
||||
/**
|
||||
* Delete locally cached avatar pictures of a contact
|
||||
*
|
||||
* @param string $avatar
|
||||
* @return bool
|
||||
*/
|
||||
public static function deleteCache(array $contact): bool
|
||||
{
|
||||
|
@ -260,7 +256,7 @@ class Avatar
|
|||
$localFile = self::getCacheFile($avatar);
|
||||
if (!empty($localFile)) {
|
||||
@unlink($localFile);
|
||||
Logger::debug('Unlink avatar', ['avatar' => $avatar, 'local' => $localFile]);
|
||||
DI::logger()->debug('Unlink avatar', ['avatar' => $avatar, 'local' => $localFile]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,11 +276,11 @@ class Avatar
|
|||
if (!file_exists($basepath)) {
|
||||
// We only automatically create the folder when it is in the web root
|
||||
if (strpos($basepath, DI::basePath()) !== 0) {
|
||||
Logger::warning('Base directory does not exist', ['directory' => $basepath]);
|
||||
DI::logger()->warning('Base directory does not exist', ['directory' => $basepath]);
|
||||
return '';
|
||||
}
|
||||
if (!mkdir($basepath, 0775)) {
|
||||
Logger::warning('Base directory could not be created', ['directory' => $basepath]);
|
||||
DI::logger()->warning('Base directory could not be created', ['directory' => $basepath]);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use Friendica\BaseEntity;
|
|||
* @property-read string $request
|
||||
* @property-read string $photo
|
||||
* @property-read string $note
|
||||
* @property-read \DateTime created
|
||||
* @property-read \DateTime $created
|
||||
* @property-read int|null $id
|
||||
*/
|
||||
class FriendSuggest extends BaseEntity
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue