forked from GNUsocial/gnu-social
Compare commits
1096 Commits
chaotic
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
010f70e432
|
|||
fc310a0b4e
|
|||
d398456be8
|
|||
3288d48b8a
|
|||
94edde001c
|
|||
41d759428f
|
|||
469cd97b9b
|
|||
8a01224feb
|
|||
61d558b371
|
|||
8c5486ba13
|
|||
a7d4a56b14
|
|||
bef23f20bc
|
|||
22ad2bd5cc
|
|||
968a425459
|
|||
30975111d9
|
|||
7c85d312ed
|
|||
c50e3324ef
|
|||
aebc5358b5
|
|||
24b3e22f73
|
|||
6e9cde8a5c
|
|||
4089fc692d
|
|||
f25759d60b
|
|||
a383021992
|
|||
d6e6e56814
|
|||
9afa265c30
|
|||
027c9a9324
|
|||
2c10ce5cfc
|
|||
c03c6f1bb5
|
|||
be5328cdc5
|
|||
4a781d483a
|
|||
5bcabbb025
|
|||
b6cd58d501
|
|||
2ba6f66b7f
|
|||
152beb5798
|
|||
96612fcd43
|
|||
4cda3fc645
|
|||
b72fcd2a05
|
|||
9018b1301a
|
|||
20901d26df
|
|||
0b3ebf841d
|
|||
fd1bd9838d
|
|||
7320c6834f
|
|||
9c533a54a7
|
|||
5be4c6a22e
|
|||
61500c5223
|
|||
f7c426e81c
|
|||
40f2f5f977
|
|||
b7b54b8a07
|
|||
a6e41d3bd8
|
|||
d4ad0cc3d4
|
|||
3af33d1317
|
|||
2448d83ace | |||
923ff309fe
|
|||
f039c86578
|
|||
e76e3b710b
|
|||
022a9476cc | |||
4e5f9a51f0
|
|||
44593f2ab4
|
|||
2ae1198704
|
|||
9e52bd127f
|
|||
41b45435ff
|
|||
e9fa41c5a8
|
|||
48c11a3fda
|
|||
fa1585bd00
|
|||
f5918d8d5c
|
|||
ff4d31404b
|
|||
ac6f2bed5e
|
|||
5cb45fcd66
|
|||
dd22894f66
|
|||
11178289fa
|
|||
1e8beefb07
|
|||
f68a2ce481
|
|||
b0f5352a53
|
|||
69ff8c2750
|
|||
355b26221d
|
|||
d4c3e26f50
|
|||
5bd5c25dcf
|
|||
e30ae79eb7
|
|||
fb861ed41f
|
|||
33bf99cfda
|
|||
4d883d1011
|
|||
1d95080f9a
|
|||
bb57d7dc10
|
|||
f3972abb70
|
|||
2e3ab5bdfb
|
|||
d23312aff9
|
|||
a43f1a641a
|
|||
31c5fd6da7
|
|||
7b3ca428e9
|
|||
df5e7b139a
|
|||
4c1fc40c43
|
|||
c381e58d33
|
|||
333567c6a1
|
|||
632a54208d
|
|||
daaf7ea236
|
|||
3019048585
|
|||
9781ddc8e0
|
|||
c12eacc758
|
|||
d13da61d30
|
|||
f64436771c
|
|||
91666f7d61
|
|||
b20a4c89fb
|
|||
6453593b0d
|
|||
f72cfd1c2b
|
|||
c0a404c640
|
|||
aec8521e4b
|
|||
eb6ff68f7a
|
|||
c86cac2095
|
|||
c14718e8dd
|
|||
ae7516c893
|
|||
32ad5dbd74
|
|||
2ea739ef61
|
|||
420b3f4aeb
|
|||
6cea2b1d00
|
|||
9c99c11790
|
|||
ecbfba1b1a
|
|||
66b39d3607
|
|||
8e627f2c18
|
|||
7cace2051f
|
|||
a4cb90ba12
|
|||
cb0093bd4a
|
|||
c804892672
|
|||
e053ee451b
|
|||
9a6fddb004
|
|||
06b9bd9910
|
|||
47daf6169a
|
|||
71b1ee7796
|
|||
4266b361c0
|
|||
504c8f8935
|
|||
c38bbed7df
|
|||
7308e66981
|
|||
2590ea7b67
|
|||
6aa61abd81
|
|||
96abf53e22
|
|||
b7d205465f
|
|||
d19c990acf
|
|||
38abbc14b9
|
|||
0eb9575534
|
|||
a02093e848
|
|||
9343d00110
|
|||
67f5421691
|
|||
bbaeaad052 | |||
5236278f45 | |||
289eef5cf7
|
|||
c155f4e30e
|
|||
5896f5bb82
|
|||
1556b3e019
|
|||
c58b9fb5b1
|
|||
97a3c067d9
|
|||
92db61a975
|
|||
05e10589c3
|
|||
a590ddd85e
|
|||
0bead1c58a
|
|||
0845224188
|
|||
1da1f0918e
|
|||
b075ab610b
|
|||
5b858a7bc1
|
|||
f760de43b0
|
|||
960675b459
|
|||
f9c1d14c7a
|
|||
ed21290ef4
|
|||
6b098a26f7
|
|||
19a966f1a9
|
|||
f5f11b6e54
|
|||
9077403f65
|
|||
bbdad515a2
|
|||
7034476cc7
|
|||
927472cf06
|
|||
b2456d8cd2
|
|||
d1e92a80e5
|
|||
af951685ed
|
|||
9c61e92257
|
|||
4297eb71a0
|
|||
b89368bf6a
|
|||
5fc5df68f5
|
|||
a83d506d6c
|
|||
56481c8289
|
|||
6d2f8daeae
|
|||
bdbd588de9
|
|||
176d604abb
|
|||
bff65afe5d
|
|||
6479b698f8
|
|||
a01914ddac
|
|||
2e3ec15827
|
|||
6deac21960
|
|||
c4de4cab32
|
|||
75af2232dc
|
|||
988d384654
|
|||
14db5d9864
|
|||
e0ebef594f
|
|||
63d26d1295
|
|||
ed850a7763
|
|||
e196a3577d
|
|||
c0e4dec674
|
|||
88ab76c480
|
|||
1f9acaf4ef
|
|||
55710aa33d
|
|||
8e743eabb9
|
|||
d34155c743
|
|||
0d6b4093fe
|
|||
400716c1b2
|
|||
75c9ffde31
|
|||
4258148a03
|
|||
6956e6907c
|
|||
7ee908f4dc
|
|||
b2d72673c7
|
|||
b51d43e6e2
|
|||
5777cdeaf9
|
|||
b0ef7599b2
|
|||
2c74bd7fb4
|
|||
b9fdaa1401
|
|||
88bb0c6b38
|
|||
df956a5f90
|
|||
aa66263b92
|
|||
ae27d95509
|
|||
2beda0dd44
|
|||
b79629b6d2
|
|||
4f6f4aa512
|
|||
3554a5c369
|
|||
5ca8842308
|
|||
5bf4a68454 | |||
903e6b33ff | |||
0a0ead3081 | |||
efeb4b4ffe | |||
780d341939 | |||
5e012c39ab | |||
787afb9b41 | |||
0e7c657301 | |||
95f92d34db | |||
3cd33fb83a | |||
c2fc2300c7
|
|||
7fd4149695
|
|||
0273c8ca24
|
|||
477518abf7
|
|||
47171069c2
|
|||
e8f57e8380
|
|||
7f3a9bc880
|
|||
263a5f67f3
|
|||
df1f12470f
|
|||
0cf53a4163
|
|||
12f3e1f406
|
|||
15f2514aa2
|
|||
900d538e26
|
|||
8f8b66c938
|
|||
3c0f6b294f
|
|||
cfd771283a
|
|||
88eea554fc
|
|||
5c8735ebea
|
|||
d2a7281a4d
|
|||
0ce686d8bb
|
|||
b4bf720b06
|
|||
0d83bbff23
|
|||
a9d710f189
|
|||
4b095961d8
|
|||
14ecf913bf
|
|||
2b4bf6c31f
|
|||
6437e68132
|
|||
37a2db3706
|
|||
362be17aba
|
|||
3a5ba9b6c4
|
|||
dd7d412e83
|
|||
593d5bf96e
|
|||
d6cf812707
|
|||
2d7b201e71
|
|||
ac5df2f6b3
|
|||
375d0097f3
|
|||
a5eb231196
|
|||
aa6886a62a
|
|||
aa1fd8ea40
|
|||
f47fedcfd4
|
|||
f206b55869
|
|||
69f5c1e312
|
|||
8b4148a00d
|
|||
df44d92bb2
|
|||
021583ea05
|
|||
4afaa6858b
|
|||
ab7d1b0370
|
|||
38225dfa6e
|
|||
154025090c
|
|||
8ec17086a0
|
|||
18f2823e14
|
|||
7dd23f3f2c
|
|||
a34f0c2534
|
|||
7d15ec1620
|
|||
2d253ee5ad
|
|||
c18879b02f
|
|||
a48e699133
|
|||
77675ea8c4
|
|||
b7b69b549e
|
|||
681f001f4e
|
|||
c5e5708915
|
|||
86e92fedc2
|
|||
8ef6aceb6a
|
|||
bf01e97533
|
|||
835a3c6701 | |||
cc0ef73799 | |||
c3eda07521 | |||
832a5c0bd9 | |||
143ecea376 | |||
0eebcdbd51 | |||
aada96beb7 | |||
218bec1826 | |||
4d2131808a | |||
4ef400f509 | |||
086754d95b | |||
5e9cd21db5 | |||
65c2c42790 | |||
d6f31ad4b4 | |||
8f7e0f2131 | |||
3af3526b5c | |||
a46140fc00 | |||
eecef99372 | |||
5543f65ce9 | |||
818a31a690 | |||
9b862d6a26 | |||
f8107c86c5 | |||
ce98e80836 | |||
75adf2e59f | |||
31518f97ee | |||
dab822037c | |||
79644d1e2b | |||
5f9b61f4bf | |||
3a6a1b71d6 | |||
f25494cd83 | |||
b79c0595d5 | |||
33cdea87ee | |||
c532fdb4c8 | |||
5cc82785c6 | |||
05fbcdefa8 | |||
dd218b04e9 | |||
059ed1fa76 | |||
f946da6f29 | |||
9e2037e086 | |||
84399a76e3 | |||
4f0bdade45 | |||
d5db350595 | |||
f5fcfe628e | |||
fde7b87c65 | |||
f841e5e0dd | |||
39ac043d59 | |||
041d19a22d | |||
b99fab00e9 | |||
88e84f2dc5 | |||
16055c7055 | |||
15c406a348 | |||
eff703ca21 | |||
2e943293e6 | |||
6aea20db05 | |||
a5a2032e75 | |||
c948ca6178 | |||
676210f76a | |||
af4b0113ba | |||
3f565442d2 | |||
4397d12fa4 | |||
c58d7e470a | |||
5a40d1f3e3 | |||
ced6e236ce | |||
d5a7f2122a | |||
d0d98a611d | |||
650bfec699 | |||
6d842d60c5 | |||
e0e1dca0f0 | |||
6374e30475 | |||
0086d8dec4 | |||
6910620d59 | |||
0629c1434d | |||
120571fa42 | |||
d9a3ecb116 | |||
1bf5e9d117 | |||
aa28251c11 | |||
c2f6665cce | |||
b196af5f36 | |||
ebfa0e2240 | |||
365a7b436f | |||
93e1e4b7a9 | |||
e5ee31a2fe | |||
e32d8711d6 | |||
78a17425f9 | |||
94b100dc06 | |||
75c494dca1 | |||
f95b8ab226 | |||
6819dd9fb7 | |||
c57a8481b1 | |||
ec0c551bb3 | |||
f17d4d2d92 | |||
255055d149 | |||
55c4ad40cd | |||
5fbc079c55 | |||
22c79db540 | |||
bb56b24d8f | |||
b2841cb5fc | |||
f264cd6125 | |||
d49de9d35e | |||
7f765c530e | |||
e699824b1d | |||
6da8cf7f14 | |||
e08767cec0 | |||
83415b7aa6 | |||
495e66f4ae | |||
17ea4ecce1 | |||
1d7375b9cb | |||
0a69f6de8c | |||
72cd2e7a30 | |||
c6389c63b8 | |||
f388554166 | |||
b4ad396cd1 | |||
c3473e45d2 | |||
075b495f5a | |||
9b3ccac246 | |||
82d9326343 | |||
464406cccc | |||
2782aa9924 | |||
1df7be7e8a | |||
792a9f097c | |||
4649ee9e71 | |||
c1db9bd0a3 | |||
cc47cda3d1 | |||
1503c98f26 | |||
b82658e345 | |||
1bad2fa050 | |||
926d0af663 | |||
0a7496de1e | |||
9814baf192 | |||
5ec7717fa1 | |||
d316f9dd6f | |||
529ec19801 | |||
e105889a59 | |||
c37a75cf7b | |||
a33a25983e | |||
2f137f8b44 | |||
0f52638a80 | |||
bbc2fe1b5a | |||
45a894c953 | |||
c8915df31e | |||
f6dea6e162 | |||
ec8ad1888a | |||
8a280c349f | |||
cbb36c9531 | |||
acf5bd1ff5 | |||
6dd6491bee | |||
2f65311ae6 | |||
cadd48922d | |||
2232f28283 | |||
b639ce906c | |||
d6414e51a2 | |||
1fda65bc3d | |||
a5505bf848 | |||
678d62781b | |||
b5ffe8a52b | |||
8e9da452c6 | |||
8fc2a83e3c | |||
f4e40002a4 | |||
8c6881f526 | |||
0802f7a9e3 | |||
d95e51a030 | |||
085a98cea3 | |||
f7af76a1ba | |||
c5b26bcffb | |||
244cc8dae1 | |||
520733888d | |||
a1cac40f6a | |||
6bfea8a0df | |||
ae29a9c00a | |||
5ddc551fd9 | |||
764ff60c34 | |||
ae91f75aeb | |||
5d4f544a03 | |||
efd2719481 | |||
66ed6fb658 | |||
6606a72e67 | |||
fc019d6a6e | |||
6be1622fd0 | |||
d0fd0e6c6c | |||
079d230959 | |||
637c25d5fe | |||
051720a686 | |||
f3c2048c62 | |||
988c5af6d3 | |||
aa58c3520c | |||
cafd9a39a0 | |||
120011a2d0 | |||
c8b2ce6694 | |||
b855dd00ac | |||
d082f4249c | |||
f11f9040b1 | |||
27dbd5521a | |||
4f3b797c80 | |||
f5df7edc6c | |||
99c4e8ded5 | |||
a8b599d213 | |||
ffaf5da984 | |||
49fa11ba07 | |||
a1546a51cd | |||
0f0851dbf3 | |||
ef617819e0 | |||
636f8d1be9 | |||
b8c73d2d2a | |||
b2aff4c75e | |||
f912236114 | |||
349df02f78 | |||
0a15ccab9b | |||
cfbb28f1ea | |||
e008bf1863 | |||
297d30706f | |||
2f570fcc2a | |||
|
ea6623f029 | ||
|
ccf4480395 | ||
|
98f072bc12 | ||
|
03aa46cf4e | ||
|
4d0f87b91b | ||
|
a4fdb193bc | ||
|
9ea47c5385 | ||
|
79f0615441 | ||
|
7e215d9f9e | ||
|
04b9c736a6 | ||
|
5e26359783 | ||
|
493476f408 | ||
|
54fd7eda06 | ||
|
f838dbe5f3 | ||
|
793e1b0417 | ||
|
66875e93f8 | ||
|
08fe5fb23f | ||
|
d4038cd520 | ||
|
f29b15924c | ||
|
f621e521f9 | ||
|
b9622e4512 | ||
|
f67c41a7ac | ||
|
19be786da8 | ||
|
e14efe86a4 | ||
|
a19b51f91e | ||
|
35d2bdfd5e | ||
|
485607169f | ||
|
ee039ab2e9 | ||
|
e2df8aec10 | ||
|
0d18615fd8 | ||
|
4f69686968 | ||
|
777b8b55fd | ||
|
7688cc39a8 | ||
|
4fd33bf37f | ||
|
3d3c560516 | ||
|
1abc3e3e7d | ||
|
f1f4ad7ba7 | ||
|
66670ff220 | ||
|
a5eca9f110 | ||
|
f9b98f87a4 | ||
|
28b337f793 | ||
|
b02564e575 | ||
|
850f1b327e | ||
|
b98db96c27 | ||
|
49b0494f28 | ||
|
27137b4762 | ||
|
81109c88c7 | ||
|
748d86d6d3 | ||
|
dde68b1d22 | ||
|
a27e3593fa | ||
|
aaa6585a1e | ||
|
a3908a22ae | ||
|
0a5ac7cf7e | ||
|
7e99d5faa8 | ||
|
b43cc4f742 | ||
|
e99d8481b5 | ||
|
5950986a6f | ||
|
c37f5a59b3 | ||
|
92ffc5644f | ||
|
439ea2c182 | ||
|
27065e5ead | ||
|
12cfb5006a | ||
|
ac16b3eff1 | ||
|
696ebe60e0 | ||
|
168b7d313a | ||
|
3a51d3ef89 | ||
|
7c8dbccee2 | ||
|
7a925cd9a6 | ||
|
0a1ea8749b | ||
|
8543c8c68e | ||
|
8bbeb79233 | ||
|
4fcde940ff | ||
|
a98e3a32f9 | ||
|
a9c35def3f | ||
|
b860c6bbb0 | ||
|
03007194c8 | ||
|
b600dc0902 | ||
|
0868880d45 | ||
|
5ec7e2e092 | ||
|
b60185a97c | ||
|
cacd9a574d | ||
|
5a7b895476 | ||
|
630ef3e826 | ||
bb4f5b88e7 | |||
23904f326d | |||
9b42f525e8 | |||
9d12dde7c1 | |||
adb5cfbb72 | |||
f8c47387c4 | |||
b337d6b2eb | |||
f486656756 | |||
2c9bd3575b | |||
e1941b6612 | |||
256169a3c4 | |||
f51a772826 | |||
0d2cf6eaa6 | |||
8a14222d51 | |||
9c2a911dab | |||
|
cfc8af675f | ||
|
b1cb923036 | ||
|
ff1d6d9df8 | ||
|
5c1b3b99f4 | ||
7e9ffbe033 | |||
|
38deea85e2 | ||
|
91eb3354e3 | ||
|
5cced1c9ed | ||
|
9cc7b6adf5 | ||
|
1f4f080bd2 | ||
|
8eb32add3a | ||
|
fdaa89e3c9 | ||
|
dd8fe29a98 | ||
|
ed9e4be6b2 | ||
|
69202ce7a0 | ||
|
88ce4cbf80 | ||
|
4c021a2838 | ||
|
4050222bc8 | ||
|
4b4da170f2 | ||
|
8ef85e90e9 | ||
|
06e92344cc | ||
|
a9944592c4 | ||
|
02c7bdf4f0 | ||
|
b34307b74c | ||
|
c43f25f4b8 | ||
|
8547c54103 | ||
|
db608ca3c1 | ||
|
abc32ecc0e | ||
|
d7ff38fe24 | ||
|
4b84ef5183 | ||
|
a7b7d487d7 | ||
|
7e7bfd1958 | ||
|
9f4a53dbbd | ||
|
96415f8523 | ||
|
e0672e559a | ||
|
c8b6db650a | ||
|
9ae31501cc | ||
|
1330c96681 | ||
|
774d7ffdf9 | ||
|
0492d71294 | ||
|
1c37eb7c72 | ||
|
34fab45b6b | ||
|
b1e49f67f4 | ||
|
6926d70543 | ||
|
09a1342588 | ||
|
ff96c2bb59 | ||
|
4ab7da32ce | ||
|
749bec5d52 | ||
|
7a68ba4f05 | ||
|
3affbc3c78 | ||
|
5663e5e58d | ||
|
922c435e28 | ||
|
5c4be9d29e | ||
|
13fb9b4698 | ||
|
8e17dd1829 | ||
|
3a4d3fc1e2 | ||
|
1f7e3a1d90 | ||
|
40aa4fa60e | ||
|
aa4418e71a | ||
|
76b8b29776 | ||
|
d862457623 | ||
|
f6a40390e0 | ||
|
1387eab434 | ||
|
ca576981a3 | ||
|
5cf7050008 | ||
|
af3ed18d48 | ||
|
54e8852fb7 | ||
|
109b17b1f9 | ||
|
a129a6e368 | ||
|
736fb672a5 | ||
|
7b467091d6 | ||
|
b364a51f80 | ||
|
8f68d7deb4 | ||
|
b5b39b5f68 | ||
|
49cd0af021 | ||
|
c423101c00 | ||
|
ebf6f8d735 | ||
|
ce94d50043 | ||
|
0ed0d0470c | ||
|
153c8d0d64 | ||
|
75bc71f473 | ||
|
29f30a6932 | ||
|
f4e52f5e11 | ||
|
902a57d10f | ||
|
928064c5ee | ||
|
492f32c555 | ||
|
b0566e7b8c | ||
|
6d3dba17d2 | ||
|
2d1200e2e6 | ||
|
a2c40163f5 | ||
|
a51c546f8c | ||
|
b2c2e6b6c6 | ||
|
fa0612c0d1 | ||
|
4d0028d95f | ||
|
54c54990a4 | ||
|
930a9a99f2 | ||
|
36aff803c6 | ||
|
b609932726 | ||
|
8f7790fa3c | ||
|
e13e763d5c | ||
|
c0caf520b8 | ||
|
1c1ef7a572 | ||
|
fefee324b4 | ||
|
07178e6ffa | ||
|
d96e4f9076 | ||
|
6445931493 | ||
|
11d6c19d65 | ||
|
b9355b49f3 | ||
|
be86a05ddb | ||
|
79be38992f | ||
|
6d92230c32 | ||
|
f5267a1975 | ||
|
5dbde32f01 | ||
|
655b5e36a4 | ||
|
a4c6fbbbd8 | ||
|
1f89f3298c | ||
|
f16fcb0200 | ||
|
253705f704 | ||
|
cf8c85f6ba | ||
|
dec35a6aa1 | ||
|
9442556c3e | ||
|
a761c4e11a | ||
|
fa40bfb8dc | ||
|
27d292affd | ||
|
dc5992bebd | ||
|
3c06a1e24f | ||
|
84cfa65bc6 | ||
|
43665749bb | ||
|
57297aba56 | ||
|
9204213dbc | ||
|
1b0cab6dc8 | ||
|
9a0c64c3d1 | ||
|
4b8e6bb198 | ||
|
624aef0a8e | ||
|
d66ec9d85c | ||
|
fc6bb1ddf6 | ||
|
475e78e13f | ||
|
8ceeb6be80 | ||
|
f76bfca921 | ||
|
0758b84d2c | ||
|
aab9212ffa | ||
|
b3c5fe9e96 | ||
|
8ca49478ab | ||
|
e142b90653 | ||
|
8276baecab | ||
|
b678ab2191 | ||
|
5ed2abaf64 | ||
|
513a1e58b8 | ||
|
d86636ebd4 | ||
|
6d1fa10965 | ||
|
86bd1dbbbf | ||
|
96aa98cbcf | ||
|
30deeaf4ef | ||
|
fe50909549 | ||
|
651af27674 | ||
|
75958fc9b4 | ||
|
036b4480f3 | ||
|
d4813b4ce9 | ||
|
21be5199cc | ||
|
8f43c12e22 | ||
|
a752a5a07c | ||
|
4945a1342f | ||
|
fd7e06bf18 | ||
|
e2960aebcb | ||
|
5b11c26e79 | ||
|
a60c79c35d | ||
|
0508886fc4 | ||
|
e0af29fd5e | ||
|
9fa363d9bf | ||
|
c3a0b08c40 | ||
|
b52d4faca7 | ||
|
7d593366c7 | ||
|
4d00a0f6dd | ||
|
648a911055 | ||
|
0d3a1cc14e | ||
|
c9b36b6030 | ||
|
52caf7cab1 | ||
|
46d946f381 | ||
|
4568578e16 | ||
|
c0b6d8807f | ||
|
c25d33e38a | ||
|
488247119a | ||
|
08c792fac7 | ||
|
e96c273351 | ||
|
a20e95fd38 | ||
|
37f21b516d | ||
|
690b8750c6 | ||
|
459a60d789 | ||
|
56c4309cb8 | ||
|
d21d4f5cb1 | ||
|
a498134b13 | ||
|
d91ab6f277 | ||
|
a5c97762e0 | ||
|
d5e41ec099 | ||
|
9e45641b7b | ||
|
b7300c6457 | ||
|
04258b6072 | ||
|
480904a4e3 | ||
|
7635f455ab | ||
|
c06346ef31 | ||
|
65d6204a01 | ||
|
bdacd638c7 | ||
|
b9a2badc31 | ||
|
be49bfa0c1 | ||
|
c1963438bc | ||
|
19e4f120c0 | ||
|
cc4a95fbd5 | ||
|
246bf30c41 | ||
|
a71f54c6bf | ||
|
e4db0eb9b9 | ||
|
e1ff2a0ef1 | ||
|
3f98f8fecf | ||
|
10010552e1 | ||
|
d38bf8ff4c | ||
|
caab08b017 | ||
|
85d8d9b268 | ||
|
a64a099d7d | ||
|
2a75237c70 | ||
|
d7801737f6 | ||
|
b2b0990bf6 | ||
|
ed84c1f8bf | ||
|
6567f10e69 | ||
|
b2dbf9bc20 | ||
|
78929629f0 | ||
|
7945a9c825 | ||
|
4c60aac8f8 | ||
|
d394f6fc9c | ||
|
605a8919a7 | ||
|
bfa3095137 | ||
|
0e401edac2 | ||
|
468d00d393 | ||
|
f5f10890b6 | ||
|
9b2db7608b | ||
|
0ca169aad2 | ||
|
9291bfbecb | ||
|
e620c20bb4 | ||
|
4b73024a57 | ||
|
b4e42d6562 | ||
|
3934d403ef | ||
|
e571c62319 | ||
|
9dffd1c93e | ||
|
34890aff90 | ||
|
503fa2e537 | ||
|
e10e6644e3 | ||
|
4d2770319e | ||
|
0cba00ebbb | ||
|
6e52fd4c95 | ||
|
9a2ac34ba3 | ||
|
e334ce9a55 | ||
|
b8a0d14fd5 | ||
|
7b0f5ab576 | ||
|
e7f541219d | ||
|
0bc59f1b9a | ||
|
8088b78a24 | ||
|
b98d01bd06 | ||
|
d0c999199b | ||
|
f907843d43 | ||
|
8aa1a3d05e | ||
|
c91c385dec | ||
|
2838aaad14 | ||
|
d6a7843240 | ||
|
51f65edb55 | ||
|
256d57adaa | ||
|
6d6b1447f8 | ||
|
801399218f | ||
|
c2e69a06b0 | ||
|
ae49f82580 | ||
|
879666fab7 | ||
|
81e45e3ace | ||
|
107351a6b5 | ||
|
292d98a33c | ||
|
72ee91a8da | ||
|
2eb61543d9 | ||
|
60002df680 | ||
|
f081d58e2b | ||
|
13244c1e37 | ||
|
71c9462d2e | ||
|
c410f9b67a | ||
|
b4fb1569ce | ||
|
fdcedb8295 | ||
|
39e3e8a04e | ||
|
7bb3717673 | ||
|
8dcf563674 | ||
|
a582cfe4f2 | ||
|
0af82054ff | ||
|
f812d9142f | ||
|
92ecb50cff | ||
|
1b2c308808 | ||
|
0c448ee83f | ||
|
a075d35c8c | ||
|
f26b488045 | ||
|
2fd81e218a | ||
|
fc4d8bcf65 | ||
|
0ef9223803 | ||
|
9bc186a072 | ||
|
70cb6d5d94 | ||
|
162a955f41 | ||
|
aadb4832bc | ||
|
0e96ffe287 | ||
|
958d5bfe22 | ||
|
c0ba6250aa | ||
|
0a6b134f23 | ||
|
a7715fc9c3 | ||
|
b508fbe3b1 | ||
|
9a9ac8b55f | ||
|
adda4caea4 | ||
|
a7ff0ef506 | ||
|
ee1c1bce80 | ||
|
7b00ab4699 | ||
|
df60e72fb3 | ||
|
d5b5d97bc1 | ||
|
640c4b2ca8 | ||
|
11822cbed0 | ||
|
9fb74c2f27 | ||
|
f361a64ab5 | ||
|
a4934a4ef3 | ||
|
46c63b3240 | ||
|
f77f56e1f2 | ||
|
2f05f05dc9 | ||
|
02b17049e3 | ||
|
ee6791fe97 | ||
|
de5554f1e2 | ||
|
e1f9143cf5 | ||
|
4fd69b684a | ||
|
c133565780 | ||
|
099be93420 | ||
|
43b7076ff8 | ||
|
49e33557e1 | ||
|
f16789f10e | ||
|
2b4540952e | ||
|
91ff4dbdec | ||
|
4cc196a69a | ||
|
7cedbcd63f | ||
|
ba7ad5fd28 | ||
|
7ca22ecc1d | ||
|
02a23a2aff | ||
|
47af6e85b8 | ||
|
04b0d63d43 | ||
|
62c9b56b3f | ||
|
155038a5c0 | ||
|
89ce298a3b | ||
|
9563fb0af3 | ||
|
2c4fcaaf07 | ||
|
3aaad123de | ||
|
7a07b95240 | ||
|
e5babcd36e | ||
|
1134fec173 | ||
|
d2b44f4400 | ||
|
aaba304ca8 | ||
|
288f8363ae | ||
|
b09e1525eb | ||
|
9fadb73ea5 | ||
|
cf1483e6b5 | ||
|
b579842eb6 | ||
|
47ab835549 | ||
|
69341880d3 | ||
|
e146ebc05b | ||
|
ceb5092b34 | ||
|
17da1f7fb5 | ||
|
43e56c08f7 | ||
|
6f9c70398b | ||
|
8b9a1dd535 | ||
|
c2d9d5b75b | ||
|
4fa6295fde | ||
|
bf4c06295a | ||
|
443a5438be | ||
|
9b88f93cad | ||
|
d6196a5e69 | ||
|
b39d43a700 | ||
|
20497bf905 | ||
|
fe20ed08d0 | ||
|
a87653860b | ||
|
9f2977bfd1 | ||
|
1e8efe180c | ||
|
29712edbd3 | ||
|
0211771d5f | ||
|
f100d33d94 | ||
|
9a05f11b65 | ||
|
b28f3ffa19 | ||
|
168d138481 | ||
|
3daa764d87 | ||
|
ff06671cd5 | ||
|
5736bd1408 | ||
|
999b31b615 | ||
|
e925c566ac | ||
|
8faf299a23 | ||
|
2985284f2b | ||
|
2d1d697498 | ||
|
57310dcb15 | ||
|
a574971f0b | ||
|
68a5551f36 | ||
|
3a6b4cca1e | ||
|
6fe35833e7 | ||
|
4b4f235481 | ||
|
6c0c84c284 | ||
|
26c966084a | ||
|
bf92c44d81 | ||
|
07422c4e1a | ||
|
6e6e50939b | ||
|
0ecb164e2e | ||
|
15cf498e75 | ||
|
377965d100 | ||
|
c9b0e994c1 | ||
|
daf4f0727d | ||
|
652c3b5d62 | ||
|
95764a0c48 | ||
|
97e9991d85 | ||
|
26be897578 | ||
|
b15fb50194 | ||
|
d7218535dd | ||
|
3108d82a4d | ||
|
d5fa31a6f5 | ||
|
a8cd9034ff | ||
|
d73840352b | ||
|
766eac8467 | ||
|
0fe5ae7675 | ||
|
66c4ab7e24 | ||
|
34f49edf2c | ||
|
27bb76706c | ||
|
ce00acdb39 | ||
|
e5a97611d0 | ||
|
d2f49e56bc | ||
|
520989bc59 | ||
|
2407853970 | ||
|
ccc0d7d401 | ||
|
ac68436b0b | ||
|
b0fece57ea | ||
|
7dda377a79 | ||
|
4a754553f7 | ||
|
074797384d | ||
|
7718b167c3 | ||
|
a2f5b77ff0 | ||
|
40ec37bd27 | ||
|
0d5f66e8b8 | ||
|
c67cf336d4 | ||
|
4efbf9361c | ||
|
87a768ac8d | ||
|
26ee98a224 | ||
|
5c1851028a | ||
|
f0b8f91a75 | ||
|
70fac546da | ||
|
80755fc6e2 | ||
|
feb3c16b3f | ||
|
cef20e1332 | ||
|
3b50815422 | ||
|
33270dabf3 | ||
|
a97c511c7a | ||
|
3b5789639b | ||
|
04a59d22a6 | ||
|
cb1944aca9 | ||
|
c2add5e1d1 | ||
|
a72e0a53e7 | ||
|
3ad81ab730 | ||
|
2afb15ee02 | ||
|
160b811669 | ||
|
fe603928e2 | ||
|
57298da60e | ||
|
d14ac1edf6 | ||
|
8ca49ab511 | ||
|
04202b59ef | ||
|
4bc3eabd29 | ||
|
36bc871c65 | ||
|
1589f6e26f | ||
|
b52f0c795e | ||
|
8f13d331ad | ||
|
b46e3d5bf4 | ||
|
8a8d0f1dcd | ||
|
e3ef58bd8e | ||
|
57f7f40fa9 | ||
|
7e4aacd342 | ||
|
1caab62200 | ||
|
6c8da48efa | ||
|
10a304ab83 | ||
|
a1d83bd2a8 | ||
|
df6da4d941 | ||
|
d8d2ad3e10 | ||
|
2f5bdeed62 | ||
|
40b0812d9b | ||
|
26ea268fed | ||
|
04a5d2bfef | ||
|
06d76a649f | ||
|
b0960c5345 | ||
|
6546c088d9 | ||
|
69550a1036 | ||
|
027726205d | ||
|
4d2b8c26fa | ||
|
cc47efe4b5 | ||
|
c0e53ae658 | ||
|
5ec23f2200 | ||
|
51d1ea4f8f | ||
|
fff0ecd1cd | ||
|
86b5bfe075 | ||
f01331671c |
@@ -1,3 +0,0 @@
|
||||
((nil . ((php-project-root . auto)
|
||||
(phpstan-executable . (root . "bin/phpstan"))
|
||||
)
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,9 +16,8 @@
|
||||
###< symfony/phpunit-bridge ###
|
||||
|
||||
###> friendsofphp/php-cs-fixer ###
|
||||
!.php-cs-fixer.php
|
||||
!.php_cs
|
||||
/.php_cs.cache
|
||||
/.php-cs-fixer.cache
|
||||
###< friendsofphp/php-cs-fixer ###
|
||||
|
||||
###> phpunit/phpunit ###
|
||||
|
@@ -1,46 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
/*
|
||||
* This document has been generated with
|
||||
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.2.1|configurator
|
||||
* https://mlocati.github.io/php-cs-fixer-configurator/#version:2.16.1|configurator
|
||||
* you can change this configuration by importing this file.
|
||||
*/
|
||||
$config = new PhpCsFixer\Config();
|
||||
return $config
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
// Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one.
|
||||
'align_multiline_comment' => ['comment_type' => 'phpdocs_like'],
|
||||
// Each element of an array must be indented exactly once.
|
||||
'array_indentation' => true,
|
||||
// Converts simple usages of `array_push($x, $y);` to `$x[] = $y;`.
|
||||
'array_push' => true,
|
||||
// PHP arrays should be declared using the configured syntax.
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
// Use the null coalescing assignment operator `??=` where possible.
|
||||
'assign_null_coalescing_to_coalesce_equal' => true,
|
||||
// Binary operators should be surrounded by space as configured.
|
||||
'binary_operator_spaces' => ['default' => 'align_single_space_minimal', 'operators' => ['??' => 'align']],
|
||||
'binary_operator_spaces' => [
|
||||
'default' => 'align_single_space_minimal',
|
||||
'operators' => ['??' => 'align'],
|
||||
],
|
||||
// There MUST be one blank line after the namespace declaration.
|
||||
'blank_line_after_namespace' => true,
|
||||
// Each element of an array must be indented exactly once.
|
||||
'array_indentation' => true,
|
||||
// Ensure there is no code on the same line as the PHP open tag and it is followed by a blank line.
|
||||
'blank_line_after_opening_tag' => true,
|
||||
'blank_line_after_opening_tag' => false,
|
||||
// The body of each structure MUST be enclosed by braces. Braces should be properly placed. Body of braces should be properly indented.
|
||||
'braces' => ['allow_single_line_anonymous_class_with_empty_body' => true, 'allow_single_line_closure' => true, 'position_after_functions_and_oop_constructs' => 'next'],
|
||||
'braces' => ['allow_single_line_closure' => true, 'position_after_functions_and_oop_constructs' => 'next',
|
||||
// 'allow_single_line_functions' => true, // Awaiting PR merge...
|
||||
],
|
||||
// A single space or none should be between cast and variable.
|
||||
'cast_spaces' => true,
|
||||
// Class, trait and interface elements must be separated with one blank line.
|
||||
'class_attributes_separation' => false,
|
||||
// Whitespace around the keywords of a class, trait or interfaces definition should be one space.
|
||||
'class_definition' => ['single_item_single_line' => true, 'single_line' => true],
|
||||
// Using `isset($var) &&` multiple times should be done in one call.
|
||||
'combine_consecutive_issets' => true,
|
||||
// Calling `unset` on multiple items should be done in one call.
|
||||
'combine_consecutive_unsets' => true,
|
||||
// Replace multiple nested calls of `dirname` by only one call with second `$level` parameter. Requires PHP >= 7.0.
|
||||
'combine_nested_dirname' => true,
|
||||
// Comments with annotation should be docblock when used on structural elements.
|
||||
'comment_to_phpdoc' => false,
|
||||
// Remove extra spaces in a nullable typehint.
|
||||
'compact_nullable_typehint' => true,
|
||||
// Concatenation should be spaced according configuration.
|
||||
@@ -49,20 +45,8 @@ return $config
|
||||
'constant_case' => true,
|
||||
// Equal sign in declare statement should be surrounded by spaces or not following configuration.
|
||||
'declare_equal_normalize' => ['space' => 'single'],
|
||||
// There must not be spaces around `declare` statement parentheses.
|
||||
'declare_parentheses' => true,
|
||||
// Force strict types declaration in all files. Requires PHP >= 7.0.
|
||||
'declare_strict_types' => true,
|
||||
// Replaces `dirname(__FILE__)` expression with equivalent `__DIR__` constant.
|
||||
'dir_constant' => true,
|
||||
// Replaces short-echo `<?=` with long format `<?php echo`/`<?php print` syntax, or vice-versa.
|
||||
'echo_tag_syntax' => true,
|
||||
// The keyword `elseif` should be used instead of `else if` so that all control keywords look like single words.
|
||||
'elseif' => true,
|
||||
// Empty loop-body must be in configured style.
|
||||
'empty_loop_body' => true,
|
||||
// Empty loop-condition must be in configured style.
|
||||
'empty_loop_condition' => true,
|
||||
// PHP code MUST use only UTF-8 without BOM (remove BOM).
|
||||
'encoding' => true,
|
||||
// Replace deprecated `ereg` regular expression functions with `preg`.
|
||||
@@ -81,30 +65,14 @@ return $config
|
||||
'function_declaration' => ['closure_function_spacing' => 'one'],
|
||||
// Ensure single space between function's argument and its typehint.
|
||||
'function_typehint_space' => true,
|
||||
// Imports or fully qualifies global classes/functions/constants.
|
||||
'global_namespace_import' => true,
|
||||
// Heredoc/nowdoc content must be properly indented. Requires PHP >= 7.3.
|
||||
'heredoc_indentation' => true,
|
||||
// Convert `heredoc` to `nowdoc` where possible.
|
||||
'heredoc_to_nowdoc' => true,
|
||||
// Function `implode` must be called with 2 arguments in the documented order.
|
||||
'implode_call' => true,
|
||||
// Pre- or post-increment and decrement operators should be used if possible.
|
||||
'increment_style' => true,
|
||||
// Code MUST use configured indentation type.
|
||||
'indentation_type' => true,
|
||||
// Lambda must not import variables it doesn't use.
|
||||
'lambda_not_used_import' => true,
|
||||
// All PHP files must use same line ending.
|
||||
'line_ending' => true,
|
||||
// Ensure there is no code on the same line as the PHP open tag.
|
||||
'linebreak_after_opening_tag' => true,
|
||||
// List (`array` destructuring) assignment should be declared using the configured syntax. Requires PHP >= 7.1.
|
||||
'list_syntax' => ['syntax' => 'short'],
|
||||
// Use `&&` and `||` logical operators instead of `and` and `or`.
|
||||
'logical_operators' => true,
|
||||
// Cast should be written in lower case.
|
||||
'lowercase_cast' => true,
|
||||
// PHP keywords MUST be in lower case.
|
||||
'lowercase_keywords' => true,
|
||||
// Class static references `self`, `static` and `parent` MUST be in lower case.
|
||||
@@ -113,14 +81,6 @@ return $config
|
||||
'magic_constant_casing' => true,
|
||||
// Magic method definitions and calls must be using the correct casing.
|
||||
'magic_method_casing' => true,
|
||||
// Replace non multibyte-safe functions with corresponding mb function.
|
||||
'mb_str_functions' => true,
|
||||
// In method arguments and method call, there MUST NOT be a space before each comma and there MUST be one space after each comma. Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line.
|
||||
'method_argument_space' => ['after_heredoc' => true, 'on_multiline' => 'ensure_fully_multiline'],
|
||||
// Method chaining MUST be properly indented. Method chaining with different levels of indentation is not supported.
|
||||
'method_chaining_indentation' => true,
|
||||
// Replace `strpos()` calls with `str_starts_with()` or `str_contains()` if possible.
|
||||
'modernize_strpos' => true,
|
||||
// Replaces `intval`, `floatval`, `doubleval`, `strval` and `boolval` function calls with according type casting operator.
|
||||
'modernize_types_casting' => true,
|
||||
// DocBlocks must start with two asterisks, multiline comments must start with a single asterisk, after the opening slash. Both must end with a single asterisk before the closing slash.
|
||||
@@ -128,17 +88,13 @@ return $config
|
||||
// Forbid multi-line whitespace before the closing semicolon or move the semicolon to the new line for chained calls.
|
||||
'multiline_whitespace_before_semicolons' => true,
|
||||
// Add leading `\` before constant invocation of internal constant to speed up resolving. Constant name match is case-sensitive, except for `null`, `false` and `true`.
|
||||
'native_constant_invocation' => true,
|
||||
'native_constant_invocation' => false,
|
||||
// Function defined by PHP should be called using the correct casing.
|
||||
'native_function_casing' => true,
|
||||
// Add leading `\` before function invocation to speed up resolving.
|
||||
'native_function_invocation' => true,
|
||||
'native_function_invocation' => false,
|
||||
// Native type hints for functions should use the correct case.
|
||||
'native_function_type_declaration_casing' => true,
|
||||
// Master language constructs shall be used instead of aliases.
|
||||
'no_alias_language_construct_call' => true,
|
||||
// Replace control structure alternative syntax to use braces.
|
||||
'no_alternative_syntax' => true,
|
||||
// There should be no empty lines after class opening brace.
|
||||
'no_blank_lines_after_class_opening' => true,
|
||||
// There should not be blank lines between docblock and the documented element.
|
||||
@@ -151,7 +107,7 @@ return $config
|
||||
'no_empty_comment' => true,
|
||||
// There should not be empty PHPDoc blocks.
|
||||
'no_empty_phpdoc' => true,
|
||||
// Remove useless (semicolon) statements.
|
||||
// Remove useless semicolon statements.
|
||||
'no_empty_statement' => true,
|
||||
// Removes extra blank lines and/or blank lines following configuration.
|
||||
'no_extra_blank_lines' => true,
|
||||
@@ -167,18 +123,18 @@ return $config
|
||||
'no_null_property_initialization' => true,
|
||||
// Short cast `bool` using double exclamation mark should not be used.
|
||||
'no_short_bool_cast' => true,
|
||||
// Replace short-echo `<?=` with long format `<?php echo` syntax.
|
||||
'no_short_echo_tag' => true,
|
||||
// Single-line whitespace before closing semicolon are prohibited.
|
||||
'no_singleline_whitespace_before_semicolons' => true,
|
||||
// There must be no space around double colons (also called Scope Resolution Operator or Paamayim Nekudotayim).
|
||||
'no_space_around_double_colon' => true,
|
||||
// When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis.
|
||||
'no_spaces_after_function_name' => true,
|
||||
// There MUST NOT be spaces around offset braces.
|
||||
'no_spaces_around_offset' => true,
|
||||
// There MUST NOT be a space after the opening parenthesis. There MUST NOT be a space before the closing parenthesis.
|
||||
'no_spaces_inside_parenthesis' => true,
|
||||
// Removes `@param`, `@return` and `@var` tags that don't provide any useful information.
|
||||
'no_superfluous_phpdoc_tags' => true,
|
||||
// Replaces superfluous `elseif` with `if`.
|
||||
'no_superfluous_elseif' => false,
|
||||
// Remove trailing commas in list function calls.
|
||||
'no_trailing_comma_in_list_call' => true,
|
||||
// PHP single-line arrays should not have trailing comma.
|
||||
@@ -194,9 +150,13 @@ return $config
|
||||
// In function arguments there must not be arguments with default values before non-default ones.
|
||||
'no_unreachable_default_argument_value' => true,
|
||||
// Variables must be set `null` instead of using `(unset)` casting.
|
||||
'no_unset_cast' => true,
|
||||
'no_unset_cast' => false,
|
||||
// Properties should be set to `null` instead of using `unset`.
|
||||
'no_unset_on_property' => true,
|
||||
// Unused `use` statements must be removed.
|
||||
'no_unused_imports' => true,
|
||||
// There should not be useless `else` cases.
|
||||
'no_useless_else' => false,
|
||||
// There should not be an empty `return` statement at the end of a function.
|
||||
'no_useless_return' => true,
|
||||
// In array declaration, there MUST NOT be a whitespace before each comma.
|
||||
@@ -207,32 +167,22 @@ return $config
|
||||
'non_printable_character' => true,
|
||||
// Array index should always be written by using square braces.
|
||||
'normalize_index_brace' => true,
|
||||
// Adds or removes `?` before type declarations for parameters with a default `null` value.
|
||||
'nullable_type_declaration_for_default_null_value' => true,
|
||||
// There should not be space before or after object operators `->` and `?->`.
|
||||
// There should not be space before or after object `T_OBJECT_OPERATOR` `->`.
|
||||
'object_operator_without_whitespace' => true,
|
||||
// Operators - when multiline - must always be at the beginning or at the end of the line.
|
||||
'operator_linebreak' => true,
|
||||
// Ordering `use` statements.
|
||||
'ordered_imports' => true,
|
||||
// Orders the elements of classes/interfaces/traits.
|
||||
'ordered_class_elements' => false,
|
||||
// PHPUnit assertion method calls like `->assertSame(true, $foo)` should be written with dedicated method like `->assertTrue($foo)`.
|
||||
'php_unit_construct' => true,
|
||||
// PHPUnit assertions like `assertInternalType`, `assertFileExists`, should be used over `assertTrue`.
|
||||
'php_unit_dedicate_assert' => true,
|
||||
// PHPUnit assertions like `assertIsArray` should be used over `assertInternalType`.
|
||||
'php_unit_dedicate_assert_internal_type' => true,
|
||||
// Usages of `->setExpectedException*` methods MUST be replaced by `->expectException*` methods.
|
||||
'php_unit_expectation' => true,
|
||||
// PHPUnit annotations should be a FQCNs including a root namespace.
|
||||
'php_unit_fqcn_annotation' => true,
|
||||
// Enforce camel (or snake) case for PHPUnit test methods, following configuration.
|
||||
'php_unit_method_casing' => true,
|
||||
// Usage of PHPUnit's mock e.g. `->will($this->returnValue(..))` must be replaced by its shorter equivalent such as `->willReturn(...)`.
|
||||
'php_unit_mock_short_will_return' => true,
|
||||
// PHPUnit classes MUST be used in namespaced version, e.g. `\PHPUnit\Framework\TestCase` instead of `\PHPUnit_Framework_TestCase`.
|
||||
'php_unit_namespaced' => true,
|
||||
// Usages of `@expectedException*` annotations MUST be replaced by `->setExpectedException*` methods.
|
||||
'php_unit_no_expectation_annotation' => true,
|
||||
// Order `@covers` annotation of PHPUnit tests.
|
||||
'php_unit_ordered_covers' => true,
|
||||
// Changes the visibility of the `setUp()` and `tearDown()` functions of PHPUnit to `protected`, to match the PHPUnit TestCase.
|
||||
'php_unit_set_up_tear_down_visibility' => true,
|
||||
// PHPUnit methods like `assertSame` should be used instead of `assertEquals`.
|
||||
@@ -243,26 +193,16 @@ return $config
|
||||
'phpdoc_add_missing_param_annotation' => true,
|
||||
// All items of the given phpdoc tags must be either left-aligned or (by default) aligned vertically.
|
||||
'phpdoc_align' => true,
|
||||
// PHPDoc annotation descriptions should not be a sentence.
|
||||
'phpdoc_annotation_without_dot' => true,
|
||||
// Docblocks should have the same indentation as the documented subject.
|
||||
'phpdoc_indent' => true,
|
||||
// Fixes PHPDoc inline tags.
|
||||
'phpdoc_inline_tag_normalizer' => true,
|
||||
// Changes doc blocks from single to multi line, or reversed. Works for class constants, properties and methods only.
|
||||
'phpdoc_line_span' => true,
|
||||
// Fix PHPDoc inline tags, make `@inheritdoc` always inline.
|
||||
'phpdoc_inline_tag' => true,
|
||||
// `@access` annotations should be omitted from PHPDoc.
|
||||
'phpdoc_no_access' => true,
|
||||
// No alias PHPDoc tags should be used.
|
||||
'phpdoc_no_alias_tag' => true,
|
||||
// `@return void` and `@return null` annotations should be omitted from PHPDoc.
|
||||
'phpdoc_no_empty_return' => true,
|
||||
// Classy that does not inherit must not have `@inheritdoc` tags.
|
||||
'phpdoc_no_useless_inheritdoc' => true,
|
||||
// Annotations in PHPDoc should be ordered so that `@param` annotations come first, then `@throws` annotations, then `@return` annotations.
|
||||
'phpdoc_order' => true,
|
||||
// Order phpdoc tags by value.
|
||||
'phpdoc_order_by_value' => ['annotations' => ['covers', 'throws']],
|
||||
// The type of `@return` annotations of methods returning a reference to itself must the configured one.
|
||||
'phpdoc_return_self_reference' => true,
|
||||
// Scalar types should always be written in the same form. `int` not `integer`, `bool` not `boolean`, `float` not `real` or `double`.
|
||||
@@ -270,18 +210,7 @@ return $config
|
||||
// Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other, and annotations of a different type are separated by a single blank line.
|
||||
'phpdoc_separation' => true,
|
||||
// Single line `@var` PHPDoc should have proper spacing.
|
||||
'phpdoc_single_line_var_spacing' => true,
|
||||
// Fixes casing of PHPDoc tags.
|
||||
'phpdoc_tag_casing' => true,
|
||||
// Would be neat, but breaks cases where the parents don't have annotations
|
||||
// // EXPERIMENTAL: Takes `@param` annotations of non-mixed types and adjusts accordingly the function signature. Requires PHP >= 7.0.
|
||||
// 'phpdoc_to_param_type' => true,
|
||||
// // EXPERIMENTAL: Takes `@var` annotation of non-mixed types and adjusts accordingly the property signature. Requires PHP >= 7.4.
|
||||
// 'phpdoc_to_property_type' => true,
|
||||
// // EXPERIMENTAL: Takes `@return` annotation of non-mixed types and adjusts accordingly the function signature. Requires PHP >= 7.0.
|
||||
// 'phpdoc_to_return_type' => true,
|
||||
// PHPDoc should start and end with content, excluding the very first and last line of the docblocks.
|
||||
'phpdoc_trim' => true,
|
||||
'phpdoc_single_line_var_spacing' => false,
|
||||
// Removes extra blank lines after summary and after description in PHPDoc.
|
||||
'phpdoc_trim_consecutive_blank_line_separation' => true,
|
||||
// The correct case must be used for standard PHP types in PHPDoc.
|
||||
@@ -290,14 +219,8 @@ return $config
|
||||
'phpdoc_types_order' => true,
|
||||
// `@var` and `@type` annotations must have type and name in the correct order.
|
||||
'phpdoc_var_annotation_correct_order' => true,
|
||||
// Converts `pow` to the `**` operator.
|
||||
'pow_to_exponentiation' => true,
|
||||
// Replaces `rand`, `srand`, `getrandmax` functions calls with their `mt_*` analogs or `random_int`.
|
||||
'random_api_migration' => true,
|
||||
// Callables must be called without using `call_user_func*` when possible.
|
||||
'regular_callable_call' => true,
|
||||
// Local, dynamic and directly referenced variables should not be assigned and directly returned by a function or method.
|
||||
'return_assignment' => true,
|
||||
// Class names should match the file name.
|
||||
'psr4' => true,
|
||||
// There should be one or no space before colon, and one space after it in return type declarations, according to configuration.
|
||||
'return_type_declaration' => true,
|
||||
// Inside class or interface element `self` should be preferred to the class name itself.
|
||||
@@ -310,26 +233,18 @@ return $config
|
||||
'short_scalar_cast' => true,
|
||||
// Converts explicit variables in double-quoted strings and heredoc syntax from simple to complex format (`${` to `{$`).
|
||||
'simple_to_complex_string_variable' => true,
|
||||
// Simplify `if` control structures that return the boolean result of their condition.
|
||||
'simplified_if_return' => true,
|
||||
// A return statement wishing to return `void` should not return `null`.
|
||||
'simplified_null_return' => true,
|
||||
// A PHP file without end tag must always end with a single empty line feed.
|
||||
'single_blank_line_at_eof' => true,
|
||||
// There should be exactly one blank line before a namespace declaration.
|
||||
'single_blank_line_before_namespace' => true,
|
||||
// There MUST NOT be more than one property or constant declared per statement.
|
||||
'single_class_element_per_statement' => true,
|
||||
// There MUST be one use keyword per declaration.
|
||||
'single_import_per_statement' => true,
|
||||
// There MUST NOT be more than one property or constant declared per statement.
|
||||
'single_class_element_per_statement' => true,
|
||||
// Each namespace use MUST go on its own line and there MUST be one blank line after the use statements block.
|
||||
'single_line_after_imports' => true,
|
||||
// Single-line comments and multi-line comments with only one line of actual content should use the `//` syntax.
|
||||
'single_line_comment_style' => true,
|
||||
// Convert double quotes to single quotes for simple strings.
|
||||
'single_quote' => true,
|
||||
// Ensures a single space after language constructs.
|
||||
'single_space_after_construct' => true,
|
||||
// Each trait `use` must be done as single statement.
|
||||
'single_trait_insert_per_statement' => true,
|
||||
// Fix whitespace after a semicolon.
|
||||
@@ -338,41 +253,26 @@ return $config
|
||||
'standardize_increment' => true,
|
||||
// Replace all `<>` with `!=`.
|
||||
'standardize_not_equals' => true,
|
||||
// String tests for empty must be done against `''`, not with `strlen`.
|
||||
'string_length_to_empty' => true,
|
||||
// A case should be followed by a colon and not a semicolon.
|
||||
'switch_case_semicolon_to_colon' => true,
|
||||
// Removes extra spaces between colon and case value.
|
||||
'switch_case_space' => true,
|
||||
// Switch case must not be ended with `continue` but with `break`.
|
||||
'switch_continue_to_break' => true,
|
||||
// Standardize spaces around ternary operator.
|
||||
'ternary_operator_spaces' => true,
|
||||
// Use the Elvis operator `?:` where possible.
|
||||
'ternary_to_elvis_operator' => true,
|
||||
// Use `null` coalescing operator `??` where possible. Requires PHP >= 7.0.
|
||||
'ternary_to_null_coalescing' => true,
|
||||
// Multi-line arrays, arguments list and parameters list must have a trailing comma.
|
||||
'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'arrays', 'parameters']],
|
||||
// Arrays should be formatted like function/method arguments, without leading or trailing single line space.
|
||||
'trim_array_spaces' => true,
|
||||
// A single space or none should be around union type operator.
|
||||
'types_spaces' => true,
|
||||
// PHP multi-line arrays should have a trailing comma.
|
||||
'trailing_comma_in_multiline_array' => true,
|
||||
// Unary operators should be placed adjacent to their operands.
|
||||
'unary_operator_spaces' => true,
|
||||
// Anonymous functions with one-liner return statement must use arrow functions.
|
||||
'use_arrow_functions' => true,
|
||||
// Visibility MUST be declared on all properties and methods; `abstract` and `final` MUST be declared before the visibility; `static` MUST be declared after the visibility.
|
||||
'visibility_required' => true,
|
||||
// In array declaration, there MUST be a whitespace after each comma.
|
||||
'whitespace_after_comma_in_array' => true,
|
||||
])
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->exclude('var')
|
||||
->exclude('docker')
|
||||
->exclude('src/Entity')
|
||||
->notPath('src/Core/DB/DefaultSettings.php')
|
||||
->in(__DIR__),
|
||||
->setFinder(PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->exclude('var')
|
||||
->exclude('docker')
|
||||
->exclude('src/Entity')
|
||||
->notPath('src/Core/DB/DefaultSettings.php')
|
||||
->in(__DIR__)
|
||||
);
|
12
CREDITS.md
12
CREDITS.md
@@ -3,21 +3,15 @@ Credits for GNU social
|
||||
The following is an incomplete list of developers
|
||||
who've worked on GNU social, or its predecessors
|
||||
StatusNet and Free Social. Apologies for any
|
||||
oversight; please let mail@diogo.site know if
|
||||
oversight; please let mattl@gnu.org know if
|
||||
anyone's been overlooked in error.
|
||||
|
||||
Current team
|
||||
------------
|
||||
* Alexei Sorokin
|
||||
* Diogo Cordeiro
|
||||
* Eliseu Amaro
|
||||
* Hugo Sales
|
||||
|
||||
V2 team
|
||||
-------
|
||||
* Diogo Cordeiro
|
||||
* Alexei Sorokin
|
||||
* Bruno Casteleiro
|
||||
* Diogo Cordeiro
|
||||
* Hugo Sales
|
||||
|
||||
Additional Contributors
|
||||
-----------------------
|
||||
|
@@ -491,7 +491,7 @@ For configuring the public stream.
|
||||
some kind of automated poster, testing bots, etc.
|
||||
|
||||
* `exclude_sources` (array, default []): Sources of notices that should be kept off of
|
||||
the public feed (because they're from automatic posters, for instance).
|
||||
the public timeline (because they're from automatic posters, for instance).
|
||||
|
||||
|
||||
throttle
|
||||
|
53
Makefile
53
Makefile
@@ -1,12 +1,5 @@
|
||||
|
||||
DIR=$(strip $(notdir $(CURDIR))) # Seems a bit hack-ish, but `basename` works differently
|
||||
|
||||
translate-container-name = $$(if docker container inspect $(1) > /dev/null 2>&1; then echo $(1); else echo $(1) | sed 'y/_/-/' ; fi)
|
||||
args = `arg="$(filter-out $@,$(MAKECMDGOALS))" && echo $${arg:-${1}}`
|
||||
|
||||
%:
|
||||
@:
|
||||
|
||||
.PHONY:
|
||||
@if ! docker info > /dev/null; then echo "Docker does not seem to be running"; exit 1; fi
|
||||
|
||||
@@ -17,50 +10,22 @@ down: .PHONY
|
||||
docker-compose down
|
||||
|
||||
redis-shell:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_redis_1) sh -c 'redis-cli'
|
||||
docker exec -it $(strip $(DIR))_redis_1 sh -c 'redis-cli'
|
||||
|
||||
php-repl: .PHONY
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c '/var/www/social/bin/console psysh'
|
||||
docker exec -it $(strip $(DIR))_php_1 sh -c '/var/www/social/bin/console psysh'
|
||||
|
||||
php-shell: .PHONY
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c 'cd /var/www/social; sh'
|
||||
docker exec -it $(strip $(DIR))_php_1 sh -c 'cd /var/www/social; sh'
|
||||
|
||||
psql-shell: .PHONY
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_db_1) sh -c "psql -U postgres social"
|
||||
|
||||
database-force-nuke:
|
||||
docker stop $(call translate-container-name,$(strip $(DIR))_worker_1) \
|
||||
&& docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c "cd /var/www/social; bin/console doctrine:database:drop --force && bin/console doctrine:database:create && bin/console doctrine:schema:update --dump-sql --force && bin/console app:populate_initial_values" \
|
||||
&& docker-compose up -d
|
||||
docker exec -it $(strip $(DIR))_db_1 sh -c "psql -U postgres social"
|
||||
|
||||
database-force-schema-update:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c "/var/www/social/bin/console doctrine:schema:update --dump-sql --force"
|
||||
docker exec -it $(strip $(DIR))_php_1 sh -c "/var/www/social/bin/console doctrine:schema:update --dump-sql --force"
|
||||
|
||||
tooling-docker: .PHONY
|
||||
@cd docker/tooling && docker-compose up -d > /dev/null 2>&1
|
||||
test: .PHONY
|
||||
cd docker/testing && docker-compose run php; docker-compose down
|
||||
|
||||
accessibility: .PHONY
|
||||
@cd docker/accessibility && docker-compose up
|
||||
|
||||
test: tooling-docker
|
||||
docker exec $(call translate-container-name,tooling_php_1) /var/tooling/coverage.sh $(call args,'')
|
||||
|
||||
cs-fixer: tooling-docker
|
||||
bin/php-cs-fixer
|
||||
|
||||
doc-check: tooling-docker
|
||||
bin/php-doc-check
|
||||
|
||||
phpstan: tooling-docker
|
||||
bin/phpstan
|
||||
|
||||
stop-tooling: .PHONY
|
||||
cd docker/tooling && docker-compose down
|
||||
|
||||
remove-var:
|
||||
rm -rf var/*
|
||||
|
||||
flush-redis-cache:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_redis_1) sh -c 'redis-cli flushall'
|
||||
|
||||
force-nuke-everything: remove-var flush-redis-cache database-force-nuke
|
||||
stop-test: .PHONY
|
||||
cd docker/testing && docker-compose down
|
||||
|
6
bin/configure
vendored
6
bin/configure
vendored
@@ -47,7 +47,7 @@ Choose whether you prefer social to handle all the services it needs though dock
|
||||
3>&1 1>&2 2>&3)
|
||||
validate_exit $?
|
||||
case ${SERVICES} in
|
||||
'docker') DOCKER='"nginx" "certbot" "php" "db" "redis" "worker"' ;; # TODO enable and configure "mail"
|
||||
'docker') DOCKER='"nginx" "certbot" "php" "db" "redis"' ;; # TODO enable and configure "mail"
|
||||
'mixed')
|
||||
DOCKER=$(${WHIPTAIL} --title 'GNU social Docker services' --clear --backtitle 'GNU social' \
|
||||
--checklist "\nPick which of the following services you'd like to add to docker-compose.\n* indicates a service that has extra configuration" 0 0 0 \
|
||||
@@ -57,7 +57,6 @@ case ${SERVICES} in
|
||||
db 'Configure a DBMS*' on \
|
||||
redis 'Configure Redis (optional, recommended)' on \
|
||||
mail 'Confugure a mail server*' on \
|
||||
worker 'Confugure container with worker queues' on \
|
||||
3>&1 1>&2 2>&3)
|
||||
validate_exit $?
|
||||
;;
|
||||
@@ -142,7 +141,6 @@ fi
|
||||
if echo "${DOCKER}" | grep -Fq '"php"'; then
|
||||
${WHIPTAIL} --title "Build PHP container locally?" --clear --backtitle 'GNU social' \
|
||||
--yesno "\nDo you want to compile the needed PHP extensions and build the container locally? (May provide better performance but requires more than 1GiB of RAM)" 0 0 \
|
||||
--defaultno \
|
||||
3>&1 1>&2 2>&3
|
||||
BUILD_PHP=$((1-$?)) # Invert output
|
||||
fi
|
||||
@@ -228,7 +226,7 @@ PROFILE=$(${WHIPTAIL} --title 'GNU social site profile' --clear --backtitle 'GNU
|
||||
public 'Make this node publicly accessible, with open registration' \
|
||||
community 'Make this node publicly accessible, but with invite-only registration' \
|
||||
isolated 'Make this node publicly accessible, with open registration but do not federate' \
|
||||
private 'Make this node publicly accessible, but with invite-only registration, only registered users can see feeds' \
|
||||
private 'Make this node publicly accessible, but with invite-only registration, only registered users can see timelines' \
|
||||
single_user 'Like public, but only allows registering one user' \
|
||||
3>&1 1>&2 2>&3)
|
||||
validate_exit $?
|
||||
|
@@ -8,9 +8,11 @@ require INSTALLDIR . '/vendor/autoload.php';
|
||||
|
||||
use Functional as F;
|
||||
|
||||
use App\Util\Functional;
|
||||
|
||||
$filenames = glob(INSTALLDIR . '/src/*/*.php');
|
||||
|
||||
$files = F\map($filenames, F\ary('file_get_contents', 1));
|
||||
$files = F\map($filenames, Functional::arity('file_get_contents', 1));
|
||||
|
||||
$old_licenses = ['/* {{{ License
|
||||
* This file is part of GNU social - https://www.gnu.org/software/social
|
||||
|
@@ -51,7 +51,7 @@ foreach ($files as $file) {
|
||||
foreach ($schema['fields'] as $field => $opts) {
|
||||
if (isset($opts['foreign key'])) {
|
||||
[$foreign_entity, $foreign_key] = explode('.', $opts['target']);
|
||||
$foreign_table = Formatting::camelCaseToSnakeCase(preg_replace('/Actor/', 'actor', $foreign_entity));
|
||||
$foreign_table = Formatting::camelCaseToSnakeCase(preg_replace('/GSActor/', 'gsactor', $foreign_entity));
|
||||
$edges[] = "{$table}:{$field} -- {$foreign_table}:{$foreign_key}";
|
||||
}
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ foreach ($files as $file) {
|
||||
$nullable = !@$schema['fields'][$field]['not null'] ? '?' : '';
|
||||
$type = types[$schema['fields'][$field]['type']];
|
||||
$type = $type !== '' ? $nullable . $type : $type;
|
||||
$method_name = str_replace([' ', 'actor'], ['', 'Actor'], ucwords(str_replace('_', ' ', $field)));
|
||||
$method_name = str_replace([' ', 'Gsactor'], ['', 'GSActor'], ucwords(str_replace('_', ' ', $field)));
|
||||
$default = @$schema['fields'][$field]['default'];
|
||||
|
||||
if (isset($default) && $nullable != '?' && $type != '\DateTimeInterface') {
|
||||
|
@@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
. bin/translate_container_name.sh
|
||||
|
||||
if [ $# -eq 1 ]; then
|
||||
docker exec -it "$(translate_container_name tooling_php_1)" /var/www/social/vendor/bin/php-cs-fixer --ansi -n --config=".php-cs-fixer.php" fix $1
|
||||
else
|
||||
docker exec -it "$(translate_container_name tooling_php_1)" /var/www/social/vendor/bin/php-cs-fixer -n --ansi --config=".php-cs-fixer.php" fix
|
||||
fi
|
1
bin/php-cs-fixer
Symbolic link
1
bin/php-cs-fixer
Symbolic link
@@ -0,0 +1 @@
|
||||
../vendor/bin/php-cs-fixer
|
@@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
. bin/translate_container_name.sh
|
||||
|
||||
docker exec -it "$(translate_container_name tooling_php_1)" /var/www/social/vendor/bin/php-doc-check src components plugins
|
1
bin/php-doc-check
Symbolic link
1
bin/php-doc-check
Symbolic link
@@ -0,0 +1 @@
|
||||
../vendor/bin/php-doc-check
|
@@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
. bin/translate_container_name.sh
|
||||
|
||||
docker exec "$(translate_container_name tooling_php_1)" /var/tooling/phpstan.sh "$@"
|
@@ -1,39 +1,28 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
root="$(git rev-parse --show-toplevel)"
|
||||
|
||||
# get the list of changed files
|
||||
staged_files="$(git status --porcelain | sed -rn "s/^[^ ][ ] (.*)/\1/p")"
|
||||
|
||||
if (! (: "${SKIP_ALL?}") 2>/dev/null) && (! (: "${SKIP_CS_FIX?}") 2>/dev/null); then
|
||||
echo "Running php-cs-fixer on edited files"
|
||||
files=""
|
||||
for staged in ${staged_files}; do
|
||||
# work only with existing files
|
||||
if [ -f "${staged}" ] && expr "${staged}" : '^.*\.php$' > /dev/null; then
|
||||
# use php-cs-fixer and get flag of correction
|
||||
files="${staged} ${files}"
|
||||
echo "Running php-cs-fixer on edited files"
|
||||
|
||||
for staged in ${staged_files}; do
|
||||
# work only with existing files
|
||||
if [ -f "${staged}" ] && [[ "${staged}" = *.php ]]
|
||||
then
|
||||
# use php-cs-fixer and get flag of correction
|
||||
if "${root}/bin/php-cs-fixer" -q fix "${staged}"
|
||||
then
|
||||
git add "${staged}" # execute git add directly
|
||||
fi
|
||||
done
|
||||
if [ -n "${files}" ]; then
|
||||
prev="${PWD}"
|
||||
cd "${root}" && make cs-fixer "${files}" || exit 1
|
||||
cd "${prev}" || exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if (! (: "${SKIP_ALL?}") 2>/dev/null) && (! (: "${SKIP_DOC_CHECK?}") 2>/dev/null); then
|
||||
echo "Running php-doc-checker"
|
||||
if echo "${staged_files}" | grep -F ".php"; then
|
||||
prev="${PWD}"
|
||||
cd "${root}" && make doc-check || exit 1
|
||||
cd "${prev}" || exit 1
|
||||
fi
|
||||
fi
|
||||
echo "Running php-doc-checker"
|
||||
|
||||
if (! (: "${SKIP_ALL?}") 2>/dev/null) && (! (: "${SKIP_PHPSTAN?}") 2>/dev/null); then
|
||||
echo "Running phpstan"
|
||||
make phpstan
|
||||
if echo "${staged_files}" | grep -F ".php"; then
|
||||
"${root}/bin/php-doc-check" src plugins components
|
||||
fi
|
||||
|
||||
# Only commit if there wasn't an error
|
||||
|
@@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
translate_container_name () {
|
||||
if docker container inspect "$1" > /dev/null 2>&1; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1" | sed 'y/_/-/'
|
||||
fi
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* Raise/update static version numbers in composer.json.
|
||||
*
|
||||
* Run on the CLI: "composer outdated --direct > outdated.txt"
|
||||
*/
|
||||
$composerJson = json_decode(file_get_contents('composer.json'), true);
|
||||
|
||||
system('composer outdated --direct > outdated.txt');
|
||||
$listOfOutdatedPackages = file('outdated.txt');
|
||||
|
||||
foreach($listOfOutdatedPackages as $line) {
|
||||
|
||||
$regexp = '/(?P<package>[\w]+\/[\w]+).*(?P<currentVersion>\d.\d.\d).*(?P<latestVersion>\d.\d.\d)/';
|
||||
preg_match($regexp, $line, $matches);
|
||||
$matches = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
|
||||
|
||||
if(isset($matches['package']))
|
||||
{
|
||||
$package = $matches['package'];
|
||||
|
||||
if(isset($composerJson['require'][$package]))
|
||||
{
|
||||
$currentVersion = $composerJson['require'][$package];
|
||||
echo sprintf('Updating %s from %s to %s', $package, $currentVersion, $matches['latestVersion']);
|
||||
$composerJson['require'][$package] = $matches['latestVersion'];
|
||||
}
|
||||
if(isset($composerJson['require-dev'][$package]))
|
||||
{
|
||||
$currentVersion = $composerJson['require-dev'][$package];
|
||||
echo sprintf('Updating %s from %s to %s', $package, $currentVersion, $matches['latestVersion']);
|
||||
$composerJson['require-dev'][$package] = $matches['latestVersion'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents('composer.json', json_encode($composerJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
namespace Component\Attachment;
|
||||
|
||||
use App\Core\Cache;
|
||||
use App\Core\Event;
|
||||
use App\Core\Modules\Component;
|
||||
use App\Core\Router\RouteLoader;
|
||||
use App\Entity\Actor;
|
||||
use App\Entity\Note;
|
||||
use App\Util\Formatting;
|
||||
use Component\Attachment\Controller as C;
|
||||
use Component\Attachment\Entity as E;
|
||||
use Doctrine\Common\Collections\ExpressionBuilder;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
class Attachment extends Component
|
||||
{
|
||||
public function onAddRoute(RouteLoader $r): bool
|
||||
{
|
||||
$r->connect('attachment_show', '/object/attachment/{id<\d+>}', [C\Attachment::class, 'attachment_show']);
|
||||
$r->connect('attachment_view', '/object/attachment/{id<\d+>}/view', [C\Attachment::class, 'attachment_view']);
|
||||
$r->connect('attachment_download', '/object/attachment/{id<\d+>}/download', [C\Attachment::class, 'attachment_download']);
|
||||
$r->connect('attachment_thumbnail', '/object/attachment/{id<\d+>}/thumbnail/{size<big|medium|small>}', [C\Attachment::class, 'attachment_thumbnail']);
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique representation of a file on disk
|
||||
*
|
||||
* This can be used in the future to deduplicate images by visual content
|
||||
*/
|
||||
public function onHashFile(string $filename, ?string &$out_hash): bool
|
||||
{
|
||||
$out_hash = hash_file(E\Attachment::FILEHASH_ALGO, $filename);
|
||||
return Event::stop;
|
||||
}
|
||||
|
||||
public function onNoteDeleteRelated(Note &$note): bool
|
||||
{
|
||||
Cache::delete("note-attachments-{$note->getId()}");
|
||||
E\AttachmentToNote::removeWhereNoteId($note->getId());
|
||||
foreach ($note->getAttachments() as $attachment) {
|
||||
$attachment->kill();
|
||||
}
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onSearchQueryAddJoins(QueryBuilder &$note_qb, QueryBuilder &$actor_qb): bool
|
||||
{
|
||||
$note_qb->leftJoin(E\AttachmentToNote::class, 'attachment_to_note', Expr\Join::WITH, 'note.id = attachment_to_note.note_id');
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate $note_expr with the criteria for looking for notes with attachments
|
||||
*/
|
||||
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr)
|
||||
{
|
||||
$include_term = str_contains($term, ':') ? explode(':', $term)[1] : $term;
|
||||
if (Formatting::startsWith($term, ['note-types:', 'notes-incude:', 'note-filter:'])) {
|
||||
if (\is_null($note_expr)) {
|
||||
$note_expr = [];
|
||||
}
|
||||
if (array_intersect(explode(',', $include_term), ['media', 'image', 'images', 'attachment']) !== []) {
|
||||
$note_expr[] = $eb->neq('attachment_to_note.note_id', null);
|
||||
} else {
|
||||
$note_expr[] = $eb->eq('attachment_to_note.note_id', null);
|
||||
}
|
||||
}
|
||||
return Event::next;
|
||||
}
|
||||
}
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
@@ -26,7 +24,6 @@ use App\Core\DB\DB;
|
||||
use App\Core\Event;
|
||||
use App\Core\GSFile;
|
||||
use App\Core\Modules\Component;
|
||||
use App\Core\Router\RouteLoader;
|
||||
use App\Core\Router\Router;
|
||||
use App\Util\Common;
|
||||
use Component\Avatar\Controller as C;
|
||||
@@ -35,111 +32,92 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class Avatar extends Component
|
||||
{
|
||||
public function onInitializeComponent()
|
||||
public function onAddRoute($r): bool
|
||||
{
|
||||
}
|
||||
|
||||
public function onAddRoute(RouteLoader $r): bool
|
||||
{
|
||||
$r->connect('avatar_actor', '/actor/{actor_id<\d+>}/avatar/{size<full|big|medium|small>?full}', [Controller\Avatar::class, 'avatar_view']);
|
||||
$r->connect('avatar_default', '/avatar/default/{size<full|big|medium|small>?full}', [Controller\Avatar::class, 'default_avatar_view']);
|
||||
$r->connect('avatar_settings', '/settings/avatar', [Controller\Avatar::class, 'settings_avatar']);
|
||||
$r->connect('avatar', '/{gsactor_id<\d+>}/avatar/{size<full|big|medium|small>?full}', [Controller\Avatar::class, 'avatar_view']);
|
||||
$r->connect('settings_avatar', '/settings/avatar', [Controller\Avatar::class, 'settings_avatar']);
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \App\Util\Exception\ClientException
|
||||
*/
|
||||
public function onPopulateSettingsTabs(Request $request, string $section, &$tabs): bool
|
||||
public function onPopulateProfileSettingsTabs(Request $request, &$tabs): bool
|
||||
{
|
||||
if ($section === 'profile') {
|
||||
$tabs[] = [
|
||||
'title' => 'Avatar',
|
||||
'desc' => 'Change your avatar.',
|
||||
'id' => 'settings-avatar',
|
||||
'controller' => C\Avatar::settings_avatar($request),
|
||||
];
|
||||
// TODO avatar template shouldn't be on settings folder
|
||||
$tabs[] = [
|
||||
'title' => 'Avatar',
|
||||
'desc' => 'Change your avatar.',
|
||||
'controller' => C\Avatar::settings_avatar($request),
|
||||
];
|
||||
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onStartTwigPopulateVars(array &$vars): bool
|
||||
{
|
||||
if (Common::user() != null) {
|
||||
$vars['user_avatar'] = self::getAvatarUrl();
|
||||
}
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onAvatarUpdate(int $actor_id): bool
|
||||
public function onGetAvatarUrl(int $gsactor_id, ?string &$url): bool
|
||||
{
|
||||
Cache::delete("avatar-{$actor_id}");
|
||||
foreach (['full', 'big', 'medium', 'small'] as $size) {
|
||||
foreach ([Router::ABSOLUTE_PATH, Router::ABSOLUTE_URL] as $type) {
|
||||
Cache::delete("avatar-url-{$actor_id}-{$size}-{$type}");
|
||||
}
|
||||
Cache::delete("avatar-file-info-{$actor_id}-{$size}");
|
||||
}
|
||||
$url = self::getAvatarUrl($gsactor_id);
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onAvatarUpdate(int $gsactor_id): bool
|
||||
{
|
||||
Cache::delete('avatar-' . $gsactor_id);
|
||||
Cache::delete('avatar-url-' . $gsactor_id);
|
||||
Cache::delete('avatar-file-info-' . $gsactor_id);
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
// UTILS ----------------------------------
|
||||
|
||||
/**
|
||||
* Get the avatar associated with the given Actor id
|
||||
* Get the avatar associated with the given GSActor id
|
||||
*/
|
||||
public static function getAvatar(?int $actor_id = null): Entity\Avatar
|
||||
public static function getAvatar(?int $gsactor_id = null): Entity\Avatar
|
||||
{
|
||||
$actor_id = $actor_id ?: Common::userId();
|
||||
return GSFile::error(
|
||||
NoAvatarException::class,
|
||||
$actor_id,
|
||||
Cache::get(
|
||||
"avatar-{$actor_id}",
|
||||
function () use ($actor_id) {
|
||||
return DB::dql(
|
||||
'select a from Component\Avatar\Entity\Avatar a '
|
||||
. 'where a.actor_id = :actor_id',
|
||||
['actor_id' => $actor_id],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
$gsactor_id = $gsactor_id ?: Common::userId();
|
||||
return GSFile::error(NoAvatarException::class,
|
||||
$gsactor_id,
|
||||
Cache::get("avatar-{$gsactor_id}",
|
||||
function () use ($gsactor_id) {
|
||||
return DB::dql('select a from Component\Avatar\Entity\Avatar a ' .
|
||||
'where a.gsactor_id = :gsactor_id',
|
||||
['gsactor_id' => $gsactor_id]);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cached avatar associated with the given Actor id, or the current user if not given
|
||||
* Get the cached avatar associated with the given GSActor id, or the current user if not given
|
||||
*/
|
||||
public static function getUrl(int $actor_id, string $size = 'full', int $type = Router::ABSOLUTE_PATH): string
|
||||
public static function getAvatarUrl(?int $gsactor_id = null, string $size = 'full'): string
|
||||
{
|
||||
try {
|
||||
return self::getAvatar($actor_id)->getUrl($size, $type);
|
||||
} catch (NoAvatarException) {
|
||||
return Router::url('avatar_default', ['size' => $size], $type);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getDimensions(int $actor_id, string $size = 'full')
|
||||
{
|
||||
try {
|
||||
$attachment = self::getAvatar($actor_id)->getAttachment();
|
||||
return ['width' => $attachment->getWidth(), 'height' => $attachment->getHeight()];
|
||||
} catch (NoAvatarException) {
|
||||
return ['width' => Common::config('thumbnail', 'small'), 'height' => Common::config('thumbnail', 'small')];
|
||||
}
|
||||
$gsactor_id = $gsactor_id ?: Common::userId();
|
||||
return Cache::get("avatar-url-{$gsactor_id}", function () use ($gsactor_id) {
|
||||
return Router::url('avatar', ['gsactor_id' => $gsactor_id, 'size' => 'full']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cached avatar file info associated with the given Actor id
|
||||
* Get the cached avatar file info associated with the given GSActor id
|
||||
*
|
||||
* Returns the avatar file's hash, mimetype, title and path.
|
||||
* Ensures exactly one cached value exists
|
||||
*/
|
||||
public static function getAvatarFileInfo(int $actor_id, string $size = 'full'): array
|
||||
public static function getAvatarFileInfo(int $gsactor_id): array
|
||||
{
|
||||
$res = Cache::get(
|
||||
"avatar-file-info-{$actor_id}-{$size}",
|
||||
function () use ($actor_id) {
|
||||
return DB::dql(
|
||||
'select f.id, f.filename, a.title, f.mimetype '
|
||||
. 'from Component\Attachment\Entity\Attachment f '
|
||||
. 'join Component\Avatar\Entity\Avatar a with f.id = a.attachment_id '
|
||||
. 'where a.actor_id = :actor_id',
|
||||
['actor_id' => $actor_id],
|
||||
);
|
||||
},
|
||||
$res = Cache::get("avatar-file-info-{$gsactor_id}",
|
||||
function () use ($gsactor_id) {
|
||||
return DB::dql('select f.id, f.filename, a.filename title, f.mimetype ' .
|
||||
'from App\Entity\Attachment f ' .
|
||||
'join Component\Avatar\Entity\Avatar a with f.id = a.attachment_id ' .
|
||||
'where a.gsactor_id = :gsactor_id',
|
||||
['gsactor_id' => $gsactor_id]);
|
||||
}
|
||||
);
|
||||
if ($res === []) { // Avatar not found
|
||||
$filepath = INSTALLDIR . '/public/assets/default-avatar.svg';
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
@@ -47,19 +45,14 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class Avatar extends Controller
|
||||
{
|
||||
public function default_avatar_view(Request $request, string $size): Response
|
||||
{
|
||||
return $this->avatar_view($request, 0, $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function avatar_view(Request $request, int $actor_id, string $size): Response
|
||||
public function avatar_view(Request $request, int $gsactor_id, string $size): Response
|
||||
{
|
||||
switch ($size) {
|
||||
case 'full':
|
||||
$res = \Component\Avatar\Avatar::getAvatarFileInfo($actor_id);
|
||||
$res = \Component\Avatar\Avatar::getAvatarFileInfo($gsactor_id);
|
||||
return M::sendFile($res['filepath'], $res['mimetype'], $res['title']);
|
||||
default:
|
||||
throw new Exception('Not implemented');
|
||||
@@ -81,52 +74,52 @@ class Avatar extends Controller
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$data = $form->getData();
|
||||
$user = Common::user();
|
||||
$actor_id = $user->getId();
|
||||
$data = $form->getData();
|
||||
$user = Common::user();
|
||||
$gsactor_id = $user->getId();
|
||||
if ($data['remove'] == true) {
|
||||
try {
|
||||
$avatar = DB::findOneBy('avatar', ['actor_id' => $actor_id]);
|
||||
$avatar = DB::findOneBy('avatar', ['gsactor_id' => $gsactor_id]);
|
||||
$avatar->delete();
|
||||
Event::handle('AvatarUpdate', [$user->getId()]);
|
||||
} catch (NotFoundException) {
|
||||
$form->addError(new FormError(_m('No avatar set, so cannot delete')));
|
||||
}
|
||||
} else {
|
||||
$attachment = null;
|
||||
if (isset($data['hidden'])) {
|
||||
// Cropped client side
|
||||
$matches = [];
|
||||
if (!empty(preg_match('/data:([^;]*)(;(base64))?,(.*)/', $data['hidden'], $matches))) {
|
||||
[, , , $encoding_user, $data_user] = $matches;
|
||||
list(, , , $encoding_user, $data_user) = $matches;
|
||||
if ($encoding_user === 'base64') {
|
||||
$data_user = base64_decode($data_user);
|
||||
$tempfile = new TemporaryFile(['prefix' => 'gs-avatar']);
|
||||
$tempfile->write($data_user);
|
||||
$attachment = GSFile::storeFileAsAttachment($tempfile);
|
||||
} else {
|
||||
Log::info('Avatar upload got an invalid encoding, something\'s fishy and/or wrong');
|
||||
}
|
||||
}
|
||||
} elseif (isset($data['avatar'])) {
|
||||
// Cropping failed (e.g. disabled js), use file as uploaded
|
||||
$file = $data['avatar'];
|
||||
$attachment = GSFile::storeFileAsAttachment($file);
|
||||
$file = $data['avatar'];
|
||||
} else {
|
||||
throw new ClientException('Invalid form');
|
||||
}
|
||||
$attachment = GSFile::sanitizeAndStoreFileAsAttachment(
|
||||
$file
|
||||
);
|
||||
// Delete current avatar if there's one
|
||||
$avatar = DB::find('avatar', ['actor_id' => $actor_id]);
|
||||
$avatar = DB::find('avatar', ['gsactor_id' => $gsactor_id]);
|
||||
$avatar?->delete();
|
||||
DB::persist($attachment);
|
||||
// Can only get new id after inserting
|
||||
DB::flush();
|
||||
DB::persist(AvatarEntity::create(['actor_id' => $actor_id, 'attachment_id' => $attachment->getId()]));
|
||||
DB::persist(AvatarEntity::create(['gsactor_id' => $gsactor_id, 'attachment_id' => $attachment->getId(), 'filename' => $file->getClientOriginalName()]));
|
||||
DB::flush();
|
||||
Event::handle('AvatarUpdate', [$user->getId()]);
|
||||
}
|
||||
}
|
||||
|
||||
return ['_template' => 'avatar/settings.html.twig', 'avatar' => $form->createView()];
|
||||
return ['_template' => 'settings/avatar.html.twig', 'avatar' => $form->createView()];
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
@@ -23,11 +21,10 @@ declare(strict_types = 1);
|
||||
|
||||
namespace Component\Avatar\Entity;
|
||||
|
||||
use App\Core\Cache;
|
||||
use App\Core\DB\DB;
|
||||
use App\Core\Entity;
|
||||
use App\Core\Router\Router;
|
||||
use Component\Attachment\Entity\Attachment;
|
||||
use App\Entity\Attachment;
|
||||
use App\Util\Common;
|
||||
use DateTimeInterface;
|
||||
|
||||
@@ -49,21 +46,21 @@ class Avatar extends Entity
|
||||
{
|
||||
// {{{ Autocode
|
||||
// @codeCoverageIgnoreStart
|
||||
private int $actor_id;
|
||||
private int $gsactor_id;
|
||||
private int $attachment_id;
|
||||
private ?string $title;
|
||||
private ?string $filename;
|
||||
private DateTimeInterface $created;
|
||||
private DateTimeInterface $modified;
|
||||
|
||||
public function setActorId(int $actor_id): self
|
||||
public function setGSActorId(int $gsactor_id): self
|
||||
{
|
||||
$this->actor_id = $actor_id;
|
||||
$this->gsactor_id = $gsactor_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActorId(): int
|
||||
public function getGSActorId(): int
|
||||
{
|
||||
return $this->actor_id;
|
||||
return $this->gsactor_id;
|
||||
}
|
||||
|
||||
public function setAttachmentId(int $attachment_id): self
|
||||
@@ -77,14 +74,20 @@ class Avatar extends Entity
|
||||
return $this->attachment_id;
|
||||
}
|
||||
|
||||
public function getTitle(): ?string
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getFilename(): ?string
|
||||
{
|
||||
return $this->title;
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
public function setTitle(?string $title): void
|
||||
/**
|
||||
* @param null|string $filename
|
||||
*/
|
||||
public function setFilename(?string $filename): void
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->filename = $filename;
|
||||
}
|
||||
|
||||
public function setCreated(DateTimeInterface $created): self
|
||||
@@ -114,15 +117,14 @@ class Avatar extends Entity
|
||||
|
||||
private ?Attachment $attachment = null;
|
||||
|
||||
public function getUrl(string $size = 'full', int $type = Router::ABSOLUTE_PATH): string
|
||||
public function getUrl(): string
|
||||
{
|
||||
$actor_id = $this->getActorId();
|
||||
return Cache::get("avatar-url-{$actor_id}-{$size}-{$type}", fn () => Router::url('avatar_actor', ['actor_id' => $actor_id, 'size' => $size], $type));
|
||||
return Router::url('avatar', ['gsactor_id' => $this->gsactor_id]);
|
||||
}
|
||||
|
||||
public function getAttachment(): Attachment
|
||||
{
|
||||
$this->attachment ??= DB::findOneBy('attachment', ['id' => $this->attachment_id]);
|
||||
$this->attachment = $this->attachment ?: DB::findOneBy('attachment', ['id' => $this->attachment_id]);
|
||||
return $this->attachment;
|
||||
}
|
||||
|
||||
@@ -138,6 +140,8 @@ class Avatar extends Entity
|
||||
|
||||
/**
|
||||
* Delete this avatar and kill corresponding attachment
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(): bool
|
||||
{
|
||||
@@ -153,13 +157,13 @@ class Avatar extends Entity
|
||||
return [
|
||||
'name' => 'avatar',
|
||||
'fields' => [
|
||||
'actor_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to actor table'],
|
||||
'gsactor_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'GSActor.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to gsactor table'],
|
||||
'attachment_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Attachment.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to attachment table'],
|
||||
'title' => ['type' => 'varchar', 'length' => 191, 'description' => 'file name of resource when available'],
|
||||
'filename' => ['type' => 'varchar', 'length' => 191, 'description' => 'file name of resource when available'],
|
||||
'created' => ['type' => 'datetime', 'not null' => true, 'description' => 'date this record was created', 'default' => 'CURRENT_TIMESTAMP'],
|
||||
'modified' => ['type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified', 'default' => 'CURRENT_TIMESTAMP'],
|
||||
],
|
||||
'primary key' => ['actor_id'],
|
||||
'primary key' => ['gsactor_id'],
|
||||
'indexes' => [
|
||||
'avatar_attachment_id_idx' => ['attachment_id'],
|
||||
],
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
|
@@ -1,3 +0,0 @@
|
||||
parameters:
|
||||
avatar:
|
||||
use_avatar: true
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
@@ -48,10 +46,10 @@ class ForeignLink
|
||||
private int $noticesync = 1;
|
||||
private int $friendsync = 2;
|
||||
private int $profilesync = 1;
|
||||
private ?DateTimeInterface $last_noticesync;
|
||||
private ?DateTimeInterface $last_friendsync;
|
||||
private DateTimeInterface $created;
|
||||
private DateTimeInterface $modified;
|
||||
private ?\DateTimeInterface $last_noticesync;
|
||||
private ?\DateTimeInterface $last_friendsync;
|
||||
private \DateTimeInterface $created;
|
||||
private \DateTimeInterface $modified;
|
||||
|
||||
public function setUserId(int $user_id): self
|
||||
{
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
@@ -44,8 +42,8 @@ class ForeignService
|
||||
private int $id;
|
||||
private string $name;
|
||||
private ?string $description;
|
||||
private DateTimeInterface $created;
|
||||
private DateTimeInterface $modified;
|
||||
private \DateTimeInterface $created;
|
||||
private \DateTimeInterface $modified;
|
||||
|
||||
public function setId(int $id): self
|
||||
{
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
@@ -44,7 +42,7 @@ class ForeignSubscription
|
||||
private int $service;
|
||||
private int $subscriber;
|
||||
private int $subscribed;
|
||||
private DateTimeInterface $created;
|
||||
private \DateTimeInterface $created;
|
||||
|
||||
public function setService(int $service): self
|
||||
{
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
@@ -45,8 +43,8 @@ class ForeignUser
|
||||
private int $service;
|
||||
private string $uri;
|
||||
private ?string $nickname;
|
||||
private DateTimeInterface $created;
|
||||
private DateTimeInterface $modified;
|
||||
private \DateTimeInterface $created;
|
||||
private \DateTimeInterface $modified;
|
||||
|
||||
public function setId(int $id): self
|
||||
{
|
||||
|
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* @author Hugo Sales <hugo@hsal.es>
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Component\Conversation\Controller;
|
||||
|
||||
use function App\Core\I18n\_m;
|
||||
use Component\Feed\Feed;
|
||||
use Component\Feed\Util\FeedController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class Conversation extends FeedController
|
||||
{
|
||||
/**
|
||||
* Render conversation page
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function showConversation(Request $request, int $conversation_id)
|
||||
{
|
||||
// TODO:
|
||||
// if note is root -> just link
|
||||
// if note is a reply -> link from above plus anchor
|
||||
|
||||
/* $notes = DB::findBy(
|
||||
table: 'note',
|
||||
criteria: ['conversation_id' => $conversation_id],
|
||||
order_by: ['created' => 'DESC', 'id' => 'DESC']
|
||||
);*/
|
||||
$data = Feed::query(query: "note-conversation:{$conversation_id}", page: $this->int('p') ?? 1);
|
||||
$notes = $data['notes'];
|
||||
return [
|
||||
'_template' => 'feed/feed.html.twig',
|
||||
'notes' => $notes,
|
||||
'should_format' => false,
|
||||
'page_title' => _m('Conversation'),
|
||||
];
|
||||
}
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* @author Hugo Sales <hugo@hsal.es>
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Component\Conversation\Controller;
|
||||
|
||||
use App\Entity\Note;
|
||||
use App\Util\Common;
|
||||
use App\Util\Exception\ClientException;
|
||||
use App\Util\Exception\NoLoggedInUser;
|
||||
use App\Util\Exception\NoSuchNoteException;
|
||||
use App\Util\Exception\ServerException;
|
||||
use Component\Feed\Util\FeedController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class Reply extends FeedController
|
||||
{
|
||||
/**
|
||||
* Controller for the note reply non-JS page
|
||||
*
|
||||
* @throws ClientException
|
||||
* @throws NoLoggedInUser
|
||||
* @throws NoSuchNoteException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function addReply(Request $request, int $note_id, int $actor_id)
|
||||
{
|
||||
$user = Common::ensureLoggedIn();
|
||||
|
||||
$note = Note::getByPK($note_id);
|
||||
if (\is_null($note) || !$note->isVisibleTo($user)) {
|
||||
throw new NoSuchNoteException();
|
||||
}
|
||||
|
||||
return [
|
||||
'_template' => 'reply/add_reply.html.twig',
|
||||
'note' => $note,
|
||||
];
|
||||
}
|
||||
}
|
@@ -1,183 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// }}}
|
||||
|
||||
namespace Component\Conversation;
|
||||
|
||||
use App\Core\DB\DB;
|
||||
use App\Core\Event;
|
||||
use function App\Core\I18n\_m;
|
||||
use App\Core\Modules\Component;
|
||||
use App\Core\Router\RouteLoader;
|
||||
use App\Core\Router\Router;
|
||||
use App\Entity\Actor;
|
||||
use App\Entity\Note;
|
||||
use App\Util\Common;
|
||||
use App\Util\Formatting;
|
||||
use Component\Conversation\Controller\Reply as ReplyController;
|
||||
use Component\Conversation\Entity\Conversation as ConversationEntity;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class Conversation extends Component
|
||||
{
|
||||
/**
|
||||
* **Assigns** the given local Note it's corresponding **Conversation**
|
||||
*
|
||||
* **If a _$parent_id_ is not given**, then the Actor is not attempting a reply,
|
||||
* therefore, we can assume (for now) that we need to create a new Conversation and assign it
|
||||
* to the newly created Note (please look at Component\Posting::storeLocalNote, where this function is used)
|
||||
*
|
||||
* **On the other hand**, given a _$parent_id_, the Actor is attempting to post a reply. Meaning that,
|
||||
* this Note conversation_id should be same as the parent Note
|
||||
*/
|
||||
public static function assignLocalConversation(Note $current_note, ?int $parent_id): void
|
||||
{
|
||||
if (!$parent_id) {
|
||||
// If none found, we don't know yet if it is a reply or root
|
||||
// Let's assume for now that it's a new conversation and deal with stitching later
|
||||
$conversation = ConversationEntity::create(['initial_note_id' => $current_note->getId()]);
|
||||
|
||||
// We need the Conversation id itself, so a persist is in order
|
||||
DB::persist($conversation);
|
||||
|
||||
// Set current_note's own conversation_id
|
||||
$current_note->setConversationId($conversation->getId());
|
||||
} else {
|
||||
// It's a reply for sure
|
||||
// Set reply_to property in newly created Note to parent's id
|
||||
$current_note->setReplyTo($parent_id);
|
||||
|
||||
// Parent will have a conversation of its own, the reply should have the same one
|
||||
$parent_note = Note::getById($parent_id);
|
||||
$current_note->setConversationId($parent_note->getConversationId());
|
||||
}
|
||||
|
||||
DB::merge($current_note);
|
||||
DB::flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML rendering event that adds a reply link as a note
|
||||
* action, if a user is logged in
|
||||
*/
|
||||
public function onAddNoteActions(Request $request, Note $note, array &$actions): bool
|
||||
{
|
||||
if (\is_null(Common::user())) {
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
// Generating URL for reply action route
|
||||
$args = ['note_id' => $note->getId(), 'actor_id' => $note->getActor()->getId()];
|
||||
$type = Router::ABSOLUTE_PATH;
|
||||
$reply_action_url = Router::url('reply_add', $args, $type);
|
||||
|
||||
$query_string = $request->getQueryString();
|
||||
// Concatenating get parameter to redirect the user to where he came from
|
||||
$reply_action_url .= !\is_null($query_string) ? '?from=' : '&from=';
|
||||
$reply_action_url .= mb_substr($query_string, 2);
|
||||
|
||||
$reply_action = [
|
||||
'url' => $reply_action_url,
|
||||
'title' => _m('Reply to this note!'),
|
||||
'classes' => 'button-container reply-button-container note-actions-unset',
|
||||
'id' => 'reply-button-container-' . $note->getId(),
|
||||
];
|
||||
|
||||
$actions[] = $reply_action;
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onAddExtraArgsToNoteContent(Request $request, Actor $actor, array $data, array &$extra_args): bool
|
||||
{
|
||||
// If Actor is adding a reply, get parent's Note id
|
||||
// Else it's null
|
||||
$extra_args['reply_to'] = $request->get('_route') === 'reply_add' ? (int) $request->get('note_id') : null;
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append on note information about user actions
|
||||
*/
|
||||
public function onAppendCardNote(array $vars, array &$result): bool
|
||||
{
|
||||
// if note is the original, append on end "user replied to this"
|
||||
// if note is the reply itself: append on end "in response to user in conversation"
|
||||
$check_user = !\is_null(Common::user());
|
||||
$note = $vars['note'];
|
||||
|
||||
$complementary_info = '';
|
||||
$reply_actor = [];
|
||||
$note_replies = $note->getReplies();
|
||||
|
||||
// Get actors who replied
|
||||
foreach ($note_replies as $reply) {
|
||||
$reply_actor[] = Actor::getByPK($reply->getActorId());
|
||||
}
|
||||
if (\count($reply_actor) < 1) {
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
// Filter out multiple replies from the same actor
|
||||
$reply_actor = array_unique($reply_actor, \SORT_REGULAR);
|
||||
|
||||
// Add to complementary info
|
||||
foreach ($reply_actor as $actor) {
|
||||
$reply_actor_url = $actor->getUrl();
|
||||
$reply_actor_nickname = $actor->getNickname();
|
||||
|
||||
if ($check_user && $actor->getId() === (Common::actor())->getId()) {
|
||||
// If the reply is yours
|
||||
$you_translation = _m('You');
|
||||
$prepend = "<a href={$reply_actor_url}>{$you_translation}</a>, " . ($prepend = &$complementary_info);
|
||||
$complementary_info = $prepend;
|
||||
} else {
|
||||
// If the repeat is from someone else
|
||||
$complementary_info .= "<a href={$reply_actor_url}>{$reply_actor_nickname}</a>, ";
|
||||
}
|
||||
}
|
||||
|
||||
$complementary_info = rtrim(trim($complementary_info), ',');
|
||||
$complementary_info .= _m(' replied to this note.');
|
||||
$result[] = Formatting::twigRenderString($complementary_info, []);
|
||||
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onAddRoute(RouteLoader $r): bool
|
||||
{
|
||||
$r->connect('reply_add', '/object/note/new?to={actor_id<\d+>}&reply_to={note_id<\d+>}', [ReplyController::class, 'addReply']);
|
||||
$r->connect('conversation', '/conversation/{conversation_id<\d+>}', [Controller\Conversation::class, 'showConversation']);
|
||||
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onPostingGetContextActor(Request $request, Actor $actor, ?Actor $context_actor)
|
||||
{
|
||||
$to_query = $request->get('actor_id');
|
||||
if (!\is_null($to_query)) {
|
||||
// Getting the actor itself
|
||||
$context_actor = Actor::getById((int) $to_query);
|
||||
return Event::stop;
|
||||
}
|
||||
return Event::next;
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
{% extends 'stdgrid.html.twig' %}
|
||||
{% import "/cards/note/view.html.twig" as noteView %}
|
||||
|
||||
{% block title %}{{ 'Reply to ' | trans }}{{ note.getActorNickname() }}{{ '\'s note.' | trans }}{% endblock %}
|
||||
|
||||
{% block stylesheets %}
|
||||
{{ parent() }}
|
||||
<link rel="stylesheet" href="{{ asset('assets/default_theme/css/pages/feeds.css') }}" type="text/css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block body %}
|
||||
{{ parent() }}
|
||||
<div class="page">
|
||||
<div class="main">
|
||||
{{ noteView.macro_note_minimal(note) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock body %}
|
@@ -1,164 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// }}}
|
||||
|
||||
namespace Component\Feed;
|
||||
|
||||
use App\Core\DB\DB;
|
||||
use App\Core\Event;
|
||||
use App\Core\Modules\Component;
|
||||
use App\Entity\Actor;
|
||||
use App\Entity\Subscription;
|
||||
use App\Util\Formatting;
|
||||
use Component\Search\Util\Parser;
|
||||
use Doctrine\Common\Collections\ExpressionBuilder;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
class Feed extends Component
|
||||
{
|
||||
/**
|
||||
* Perform a high level query on notes or actors
|
||||
*
|
||||
* Supports a variety of query terms and is used both in feeds and
|
||||
* in search. Uses query builders to allow for extension
|
||||
*/
|
||||
public static function query(string $query, int $page, ?string $language = null, ?Actor $actor = null): array
|
||||
{
|
||||
$note_criteria = null;
|
||||
$actor_criteria = null;
|
||||
if (!empty($query = trim($query))) {
|
||||
[$note_criteria, $actor_criteria] = Parser::parse($query, $language, $actor);
|
||||
}
|
||||
$note_qb = DB::createQueryBuilder();
|
||||
$actor_qb = DB::createQueryBuilder();
|
||||
$note_qb->select('note')->from('App\Entity\Note', 'note')->orderBy('note.created', 'DESC')->orderBy('note.id', 'DESC');
|
||||
$actor_qb->select('actor')->from('App\Entity\Actor', 'actor')->orderBy('actor.created', 'DESC')->orderBy('actor.id', 'DESC');
|
||||
Event::handle('SearchQueryAddJoins', [&$note_qb, &$actor_qb, $note_criteria, $actor_criteria]);
|
||||
|
||||
$notes = [];
|
||||
$actors = [];
|
||||
if (!\is_null($note_criteria)) {
|
||||
$note_qb->addCriteria($note_criteria);
|
||||
}
|
||||
$notes = $note_qb->getQuery()->execute();
|
||||
|
||||
if (!\is_null($actor_criteria)) {
|
||||
$actor_qb->addCriteria($actor_criteria);
|
||||
}
|
||||
$actors = $actor_qb->getQuery()->execute();
|
||||
|
||||
// TODO: Enforce scoping on the notes before returning
|
||||
return ['notes' => $notes ?? null, 'actors' => $actors ?? null];
|
||||
}
|
||||
|
||||
public function onSearchQueryAddJoins(QueryBuilder &$note_qb, QueryBuilder &$actor_qb)
|
||||
{
|
||||
$note_qb->leftJoin(Subscription::class, 'subscription', Expr\Join::WITH, 'note.actor_id = subscription.subscribed')
|
||||
->leftJoin(Actor::class, 'note_actor', Expr\Join::WITH, 'note.actor_id = note_actor.id');
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert $term to $note_expr and $actor_expr, search criteria. Handles searching for text
|
||||
* notes, for different types of actors and for the content of text notes
|
||||
*/
|
||||
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr)
|
||||
{
|
||||
if (str_contains($term, ':')) {
|
||||
$term = explode(':', $term);
|
||||
if (Formatting::startsWith($term[0], 'note-')) {
|
||||
switch ($term[0]) {
|
||||
case 'note-local':
|
||||
$note_expr = $eb->eq('note.is_local', filter_var($term[1], \FILTER_VALIDATE_BOOLEAN));
|
||||
break;
|
||||
case 'note-types':
|
||||
case 'notes-include':
|
||||
case 'note-filter':
|
||||
if (\is_null($note_expr)) {
|
||||
$note_expr = [];
|
||||
}
|
||||
if (array_intersect(explode(',', $term[1]), ['text', 'words']) !== []) {
|
||||
$note_expr[] = $eb->neq('note.content', null);
|
||||
} else {
|
||||
$note_expr[] = $eb->eq('note.content', null);
|
||||
}
|
||||
break;
|
||||
case 'note-conversation':
|
||||
$note_expr = $eb->eq('note.conversation_id', (int) trim($term[1]));
|
||||
break;
|
||||
case 'note-from':
|
||||
case 'notes-from':
|
||||
$subscribed_expr = $eb->eq('subscription.subscriber', $actor->getId());
|
||||
$type_consts = [];
|
||||
if ($term[1] === 'subscribed') {
|
||||
$type_consts = null;
|
||||
}
|
||||
foreach (explode(',', $term[1]) as $from) {
|
||||
if (str_starts_with($from, 'subscribed-')) {
|
||||
[, $type] = explode('-', $from);
|
||||
if (\in_array($type, ['actor', 'actors'])) {
|
||||
$type_consts = null;
|
||||
} else {
|
||||
$type_consts[] = \constant(Actor::class . '::' . mb_strtoupper($type));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (\is_null($type_consts)) {
|
||||
$note_expr = $subscribed_expr;
|
||||
} elseif (!empty($type_consts)) {
|
||||
$note_expr = $eb->andX($subscribed_expr, $eb->in('note_actor.type', $type_consts));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} elseif (Formatting::startsWith($term, 'actor-')) {
|
||||
switch ($term[0]) {
|
||||
case 'actor-types':
|
||||
case 'actors-include':
|
||||
case 'actor-filter':
|
||||
case 'actor-local':
|
||||
if (\is_null($actor_expr)) {
|
||||
$actor_expr = [];
|
||||
}
|
||||
foreach (
|
||||
[
|
||||
Actor::PERSON => ['person', 'people'],
|
||||
Actor::GROUP => ['group', 'groups'],
|
||||
Actor::ORGANIZATION => ['org', 'orgs', 'organization', 'organizations', 'organisation', 'organisations'],
|
||||
Actor::BUSINESS => ['business', 'businesses'],
|
||||
Actor::BOT => ['bot', 'bots'],
|
||||
] as $type => $match) {
|
||||
if (array_intersect(explode(',', $term[1]), $match) !== []) {
|
||||
$actor_expr[] = $eb->eq('actor.type', $type);
|
||||
} else {
|
||||
$actor_expr[] = $eb->neq('actor.type', $type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$note_expr = $eb->contains('note.content', $term);
|
||||
}
|
||||
return Event::next;
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* Base class for feed controllers
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @category Controller
|
||||
*
|
||||
* @author Hugo Sales <hugo@hsal.es>
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Component\Feed\Util;
|
||||
|
||||
use App\Core\Controller;
|
||||
use App\Core\Event;
|
||||
use App\Util\Common;
|
||||
|
||||
abstract class FeedController extends Controller
|
||||
{
|
||||
/**
|
||||
* Post process the result of a feed controller, to remove any
|
||||
* notes or actors the user specified, as well as format the raw
|
||||
* list of notes into a usable format
|
||||
*/
|
||||
public static function post_process(array $result): array
|
||||
{
|
||||
$actor = Common::actor();
|
||||
|
||||
if (\array_key_exists('notes', $result)) {
|
||||
$notes = $result['notes'];
|
||||
Event::handle('FilterNoteList', [$actor, &$notes, $result['request']]);
|
||||
Event::handle('FormatNoteList', [$notes, &$result['notes']]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
{% extends 'stdgrid.html.twig' %}
|
||||
{% import '/cards/note/view.html.twig' as noteView %}
|
||||
|
||||
{% block title %}{% if page_title is defined %}{{ page_title | trans }}{% endif %}{% endblock %}
|
||||
|
||||
{% block stylesheets %}
|
||||
{{ parent() }}
|
||||
<link rel="stylesheet" href="{{ asset('assets/default_theme/css/pages/feeds.css') }}" type="text/css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block body %}
|
||||
<header class="feed-header">
|
||||
{% if page_title is defined %}
|
||||
<h1>{{ page_title | trans }} {{ 'feed' | trans }}</h1>
|
||||
{% endif %}
|
||||
<nav class="feed-actions" role=navigation>
|
||||
{% for block in handle_event('AddFeedActions', app.request) %}
|
||||
{{ block | raw }}
|
||||
{% endfor %}
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
{# Backwards compatibility with hAtom 0.1 #}
|
||||
<main class="feed" tabindex="0" role="feed">
|
||||
<div class="h-feed hfeed notes">
|
||||
{% if notes is defined and notes is not empty %}
|
||||
{% for conversation in notes %}
|
||||
{% block current_note %}
|
||||
{% if conversation is instanceof('array') %}
|
||||
{{ noteView.macro_note(conversation['note'], conversation['replies']) }}
|
||||
{% else %}
|
||||
{{ noteView.macro_note(conversation) }}
|
||||
{% endif %}
|
||||
<hr tabindex="0" title="{{ 'End of note and replies.' | trans }}">
|
||||
{% endblock current_note %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div id="empty-notes"><h1>{% trans %}No notes here.{% endtrans %}</h1></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</main>
|
||||
{% endblock body %}
|
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* Handle network public feed
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @category Controller
|
||||
*
|
||||
* @author Diogo Peralta Cordeiro <@diogo.site>
|
||||
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Component\FreeNetwork\Controller;
|
||||
|
||||
use App\Core\DB\DB;
|
||||
use function App\Core\I18n\_m;
|
||||
use App\Util\Common;
|
||||
use Component\Feed\Feed;
|
||||
use Component\Feed\Util\FeedController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class Feeds extends FeedController
|
||||
{
|
||||
/**
|
||||
* The Meteorites feed represents every post coming from the
|
||||
* known fediverse to this instance's inbox. I.e., it's our
|
||||
* known network and excludes everything that is local only
|
||||
* or federated out.
|
||||
*/
|
||||
public function network(Request $request): array
|
||||
{
|
||||
Common::ensureLoggedIn();
|
||||
$data = Feed::query(
|
||||
query: 'note-local:false',
|
||||
page: $this->int('p'),
|
||||
language: Common::actor()?->getTopLanguage()?->getLocale(),
|
||||
);
|
||||
return [
|
||||
'_template' => 'feed/feed.html.twig',
|
||||
'page_title' => _m('Meteorites'),
|
||||
'should_format' => true,
|
||||
'notes' => $data['notes'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The Planetary System feed represents every planet-centric post, i.e.,
|
||||
* everything that is local or comes from outside with relation to local actors
|
||||
* or posts.
|
||||
*/
|
||||
public function clique(Request $request): array
|
||||
{
|
||||
Common::ensureLoggedIn();
|
||||
$notes = DB::dql(
|
||||
<<<'EOF'
|
||||
SELECT n FROM \App\Entity\Note AS n
|
||||
WHERE n.is_local = true OR n.id IN (
|
||||
SELECT act.object_id FROM \App\Entity\Activity AS act
|
||||
WHERE act.object_type = 'note' AND act.id IN
|
||||
(SELECT att.activity_id FROM \Component\Notification\Entity\Notification AS att WHERE att.target_id IN
|
||||
(SELECT a.id FROM \App\Entity\Actor a WHERE a.is_local = true))
|
||||
)
|
||||
ORDER BY n.created DESC, n.id DESC
|
||||
EOF,
|
||||
);
|
||||
return [
|
||||
'_template' => 'feed/feed.html.twig',
|
||||
'page_title' => _m('Planetary System'),
|
||||
'should_format' => true,
|
||||
'notes' => $notes,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The Galaxy feed represents everything that is federated out or federated in.
|
||||
* Given that any local post can be federated out and it's hard to specifically exclude these,
|
||||
* we simply return everything here, local and remote posts. So, a galaxy.
|
||||
*/
|
||||
public function federated(Request $request): array
|
||||
{
|
||||
Common::ensureLoggedIn();
|
||||
$data = Feed::query(
|
||||
query: '',
|
||||
page: $this->int('p'),
|
||||
language: Common::actor()?->getTopLanguage()?->getLocale(),
|
||||
);
|
||||
return [
|
||||
'_template' => 'feed/feed.html.twig',
|
||||
'page_title' => _m('Galaxy'),
|
||||
'should_format' => true,
|
||||
'notes' => $data['notes'],
|
||||
];
|
||||
}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author James Walker <james@status.net>
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
*/
|
||||
|
||||
namespace Component\FreeNetwork\Controller;
|
||||
|
||||
use App\Core\Controller;
|
||||
use App\Core\Event;
|
||||
use Component\FreeNetwork\Util\Discovery;
|
||||
use Component\FreeNetwork\Util\XrdController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use XML_XRD;
|
||||
|
||||
class HostMeta extends XrdController
|
||||
{
|
||||
protected string $default_mimetype = Discovery::XRD_MIMETYPE;
|
||||
|
||||
public function setXRD()
|
||||
{
|
||||
if (Event::handle('StartHostMetaLinks', [&$this->xrd->links])) {
|
||||
Event::handle('EndHostMetaLinks', [&$this->xrd->links]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Component\FreeNetwork\Controller;
|
||||
|
||||
/**
|
||||
* @package WebFingerPlugin
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
use App\Entity\LocalUser;
|
||||
use App\Util\Common;
|
||||
use Component\FreeNetwork\Util\Discovery;
|
||||
use Component\FreeNetwork\Util\XrdController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class OwnerXrd extends XrdController
|
||||
{
|
||||
protected string $default_mimetype = Discovery::XRD_MIMETYPE;
|
||||
|
||||
public function handle(Request $request): array
|
||||
{
|
||||
$user = LocalUser::siteOwner();
|
||||
|
||||
$nick = common_canonical_nickname($user->nickname);
|
||||
$this->resource = 'acct:' . $nick . '@' . Common::config('site', 'server');
|
||||
|
||||
// We have now set $args['resource'] to the configured value, since
|
||||
// only this local site configuration knows who the owner is!
|
||||
return parent::handle($request);
|
||||
}
|
||||
|
||||
protected function setXRD()
|
||||
{
|
||||
// Check to see if a $config['webfinger']['owner'] has been set
|
||||
// and then make sure 'subject' is set to that primary identity.
|
||||
if (!empty($owner = Common::config('webfinger', 'owner'))) {
|
||||
$this->xrd->aliases[] = $this->xrd->subject;
|
||||
$this->xrd->subject = Discovery::normalize($owner);
|
||||
} else {
|
||||
$this->xrd->subject = $this->resource;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Component\FreeNetwork\Controller;
|
||||
|
||||
use App\Core\Event;
|
||||
use function App\Core\I18n\_m;
|
||||
use App\Util\Exception\ClientException;
|
||||
use App\Util\Exception\NoSuchActorException;
|
||||
use Component\FreeNetwork\Util\Discovery;
|
||||
use Component\FreeNetwork\Util\WebfingerResource;
|
||||
use Component\FreeNetwork\Util\XrdController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @package WebFingerPlugin
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @author Diogo Peralta Cordeiro
|
||||
*/
|
||||
class Webfinger extends XrdController
|
||||
{
|
||||
protected $resource; // string with the resource URI
|
||||
protected $target; // object of the WebFingerResource class
|
||||
|
||||
public function handle(Request $request): array
|
||||
{
|
||||
// throws exception if resource is empty
|
||||
$this->resource = Discovery::normalize($this->string('resource'));
|
||||
|
||||
try {
|
||||
if (Event::handle('StartGetWebFingerResource', [$this->resource, &$this->target, $this->params()])) {
|
||||
Event::handle('EndGetWebFingerResource', [$this->resource, &$this->target, $this->params()]);
|
||||
}
|
||||
} catch (NoSuchActorException $e) {
|
||||
throw new ClientException($e->getMessage(), 404);
|
||||
}
|
||||
|
||||
if (!$this->target instanceof WebfingerResource) {
|
||||
// TRANS: Error message when an object URI which we cannot find was requested
|
||||
throw new ClientException(_m('Resource not found in local database.'), 404);
|
||||
}
|
||||
|
||||
return parent::handle($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures $this->xrd which will later be printed.
|
||||
*/
|
||||
protected function setXRD()
|
||||
{
|
||||
$this->xrd->subject = $this->resource;
|
||||
|
||||
foreach ($this->target->getAliases() as $alias) {
|
||||
if ($alias != $this->xrd->subject && !in_array($alias, $this->xrd->aliases)) {
|
||||
$this->xrd->aliases[] = $alias;
|
||||
}
|
||||
}
|
||||
|
||||
$this->target->updateXRD($this->xrd);
|
||||
}
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
StartHostMetaLinks: Start /.well-known/host-meta links
|
||||
- &links: array containing the links elements to be written
|
||||
|
||||
EndHostMetaLinks: End /.well-known/host-meta links
|
||||
- &links: array containing the links elements to be written
|
||||
|
||||
StartGetWebFingerResource: Get a WebFingerResource extended object by resource string
|
||||
- $resource String that contains the requested URI
|
||||
- &$target WebFingerResource extended object goes here
|
||||
- $args Array which may contains arguments such as 'rel' filtering values
|
||||
|
||||
EndGetWebFingerResource: Last attempts getting a WebFingerResource object
|
||||
- $resource String that contains the requested URI
|
||||
- &$target WebFingerResource extended object goes here
|
||||
- $args Array which may contains arguments such as 'rel' filtering values
|
||||
|
||||
StartWebFingerReconstruction: Generate an acct: uri from a Profile object
|
||||
- $profile: Profile object for which we want a WebFinger ID
|
||||
- &$acct: String reference where reconstructed ID is stored
|
||||
|
||||
EndWebFingerReconstruction: Last attempts to generate an acct: uri from a Profile object
|
||||
- $profile: Profile object for which we want a WebFinger ID
|
||||
- &$acct: String reference where reconstructed ID is stored
|
||||
|
||||
StartWebFingerNoticeLinks: About to set links for the resource descriptor of a Notice
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Notice being shown
|
||||
|
||||
EndWebFingerNoticeLinks: Done with links for the resource descriptor of a Notice
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Notice being shown
|
||||
|
||||
StartWebFingerProfileLinks: About to set links for the resource descriptor of a Profile
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Profile being shown
|
||||
|
||||
EndWebFingerProfileLinks: Done with links for the resource descriptor of a Profile
|
||||
- $xrd: XML_XRD object being shown
|
||||
- $target: Profile being shown
|
||||
|
||||
StartDiscoveryMethodRegistration
|
||||
- $disco: Discovery object that accepts the registrations
|
||||
|
||||
EndDiscoveryMethodRegistration: Register remote URI discovery methods
|
||||
- $disco: Discovery object that accepts the registrations
|
||||
|
@@ -1,180 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
// {{{ License
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* ActivityPub implementation for GNU social
|
||||
*
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author Diogo Peralta Cordeiro <@diogo.site
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Component\FreeNetwork\Entity;
|
||||
|
||||
use App\Core\Cache;
|
||||
use App\Core\DB\DB;
|
||||
use App\Core\Entity;
|
||||
use function App\Core\I18n\_m;
|
||||
use App\Core\Log;
|
||||
use App\Entity\Actor;
|
||||
use Component\FreeNetwork\Util\Discovery;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use Plugin\ActivityPub\Util\DiscoveryHints;
|
||||
use Plugin\ActivityPub\Util\Explorer;
|
||||
|
||||
/**
|
||||
* Table Definition for free_network_actor_protocol
|
||||
*
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class FreeNetworkActorProtocol extends Entity
|
||||
{
|
||||
// {{{ Autocode
|
||||
// @codeCoverageIgnoreStart;
|
||||
private int $actor_id;
|
||||
private ?string $protocol;
|
||||
private ?string $addr;
|
||||
private DateTimeInterface $created;
|
||||
private DateTimeInterface $modified;
|
||||
|
||||
public function getActorId(): int
|
||||
{
|
||||
return $this->actor_id;
|
||||
}
|
||||
|
||||
public function setActorId(int $actor_id): self
|
||||
{
|
||||
$this->actor_id = $actor_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setProtocol(?string $protocol): self
|
||||
{
|
||||
$this->protocol = $protocol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProtocol(): ?string
|
||||
{
|
||||
return $this->protocol;
|
||||
}
|
||||
|
||||
public function setAddr(string $addr): self
|
||||
{
|
||||
$this->addr = $addr;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAddr(): string
|
||||
{
|
||||
return $this->addr;
|
||||
}
|
||||
|
||||
public function getCreated(): DateTimeInterface
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
public function setCreated(DateTimeInterface $created): self
|
||||
{
|
||||
$this->created = $created;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getModified(): DateTimeInterface
|
||||
{
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
public function setModified(DateTimeInterface $modified): self
|
||||
{
|
||||
$this->modified = $modified;
|
||||
return $this;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
// }}} Autocode
|
||||
|
||||
public static function protocolSucceeded(string $protocol, int|Actor $actor_id, string $addr): void
|
||||
{
|
||||
$actor_id = is_int($actor_id) ? $actor_id : $actor_id->getId();
|
||||
$attributed_protocol = self::getByPK(['actor_id' => $actor_id]);
|
||||
if (is_null($attributed_protocol)) {
|
||||
$attributed_protocol = self::create([
|
||||
'actor_id' => $actor_id,
|
||||
'protocol' => $protocol,
|
||||
'addr' => Discovery::normalize($addr),
|
||||
]);
|
||||
} else {
|
||||
$attributed_protocol->setProtocol($protocol);
|
||||
}
|
||||
DB::wrapInTransaction(fn() => DB::persist($attributed_protocol));
|
||||
}
|
||||
|
||||
public static function canIActor(string $protocol, int|Actor $actor_id): bool
|
||||
{
|
||||
$actor_id = is_int($actor_id) ? $actor_id : $actor_id->getId();
|
||||
$attributed_protocol = self::getByPK(['actor_id' => $actor_id])?->getProtocol();
|
||||
if (is_null($attributed_protocol)) {
|
||||
// If it is not attributed, you can go ahead.
|
||||
return true;
|
||||
} else {
|
||||
// If it is attributed, you can on the condition that you're assigned to it.
|
||||
return $attributed_protocol === $protocol;
|
||||
}
|
||||
}
|
||||
|
||||
public static function canIAddr(string $protocol, string $target): bool
|
||||
{
|
||||
// Normalize $addr, i.e. add 'acct:' if missing
|
||||
$addr = Discovery::normalize($target);
|
||||
$attributed_protocol = self::getByPK(['addr' => $addr])?->getProtocol();
|
||||
if (is_null($attributed_protocol)) {
|
||||
// If it is not attributed, you can go ahead.
|
||||
return true;
|
||||
} else {
|
||||
// If it is attributed, you can on the condition that you're assigned to it.
|
||||
return $attributed_protocol === $protocol;
|
||||
}
|
||||
}
|
||||
|
||||
public static function schemaDef(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'free_network_actor_protocol',
|
||||
'fields' => [
|
||||
'actor_id' => ['type' => 'int', 'not null' => true],
|
||||
'protocol' => ['type' => 'varchar', 'length' => 32, 'description' => 'the protocol plugin that should handle federation of this actor'],
|
||||
'addr' => ['type' => 'text', 'not null' => true, 'description' => 'webfinger acct'],
|
||||
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
|
||||
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
|
||||
],
|
||||
'primary key' => ['actor_id'],
|
||||
'foreign keys' => [
|
||||
'activitypub_actor_actor_id_fkey' => ['actor', ['actor_id' => 'id']],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Class for an exception when a WebFinger acct: URI can not be constructed
|
||||
* using the data we have in a Profile.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Exception
|
||||
* @package StatusNet
|
||||
*
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
*
|
||||
* @see http://status.net/
|
||||
*/
|
||||
|
||||
namespace Component\FreeNetwork\Exception;
|
||||
|
||||
use function App\Core\I18n\_m;
|
||||
use App\Util\Exception\ServerException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class for an exception when a WebFinger acct: URI can not be constructed
|
||||
* using the data we have in a Profile.
|
||||
*
|
||||
* @category Exception
|
||||
* @package StatusNet
|
||||
*
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
*
|
||||
* @see http://status.net/
|
||||
*/
|
||||
class WebfingerReconstructionException extends ServerException
|
||||
{
|
||||
public function __construct(string $message = '', int $code = 500, Throwable $previous = null)
|
||||
{
|
||||
// We could log an entry here with the search parameters
|
||||
parent::__construct(_m('WebFinger URI generation failed.'));
|
||||
}
|
||||
}
|
@@ -1,516 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
namespace Component\FreeNetwork;
|
||||
|
||||
use App\Core\DB\DB;
|
||||
use App\Core\Event;
|
||||
use App\Core\GSFile;
|
||||
use App\Core\HTTPClient;
|
||||
use function App\Core\I18n\_m;
|
||||
use App\Core\Log;
|
||||
use App\Core\Modules\Component;
|
||||
use App\Core\Router\RouteLoader;
|
||||
use App\Core\Router\Router;
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Actor;
|
||||
use App\Entity\LocalUser;
|
||||
use App\Entity\Note;
|
||||
use App\Util\Common;
|
||||
use App\Util\Exception\ClientException;
|
||||
use App\Util\Exception\NicknameEmptyException;
|
||||
use App\Util\Exception\NicknameException;
|
||||
use App\Util\Exception\NicknameInvalidException;
|
||||
use App\Util\Exception\NicknameNotAllowedException;
|
||||
use App\Util\Exception\NicknameTakenException;
|
||||
use App\Util\Exception\NicknameTooLongException;
|
||||
use App\Util\Exception\NoSuchActorException;
|
||||
use App\Util\Exception\ServerException;
|
||||
use App\Util\Nickname;
|
||||
use Component\FreeNetwork\Controller\Feeds;
|
||||
use Component\FreeNetwork\Controller\HostMeta;
|
||||
use Component\FreeNetwork\Controller\OwnerXrd;
|
||||
use Component\FreeNetwork\Controller\Webfinger;
|
||||
use Component\FreeNetwork\Util\Discovery;
|
||||
use Component\FreeNetwork\Util\WebfingerResource;
|
||||
use Component\FreeNetwork\Util\WebfingerResource\WebfingerResourceActor;
|
||||
use Component\FreeNetwork\Util\WebfingerResource\WebfingerResourceNote;
|
||||
use Exception;
|
||||
use Plugin\ActivityPub\Entity\ActivitypubActivity;
|
||||
use Plugin\ActivityPub\Util\TypeResponse;
|
||||
use const PREG_SET_ORDER;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use XML_XRD;
|
||||
use XML_XRD_Element_Link;
|
||||
|
||||
/**
|
||||
* Implements WebFinger (RFC7033) for GNU social, as well as Link-based Resource Descriptor Discovery based on RFC6415,
|
||||
* Web Host Metadata ('.well-known/host-meta') resource.
|
||||
*
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @author Diogo Peralta Cordeiro <mail@diogo.site>
|
||||
*/
|
||||
class FreeNetwork extends Component
|
||||
{
|
||||
public const PLUGIN_VERSION = '0.1.0';
|
||||
|
||||
public const OAUTH_ACCESS_TOKEN_REL = 'http://apinamespace.org/oauth/access_token';
|
||||
public const OAUTH_REQUEST_TOKEN_REL = 'http://apinamespace.org/oauth/request_token';
|
||||
public const OAUTH_AUTHORIZE_REL = 'http://apinamespace.org/oauth/authorize';
|
||||
|
||||
public function onAddRoute(RouteLoader $m): bool
|
||||
{
|
||||
// Feeds
|
||||
$m->connect('feed_network', '/feed/network', [Feeds::class, 'network']);
|
||||
$m->connect('feed_clique', '/feed/clique', [Feeds::class, 'clique']);
|
||||
$m->connect('feed_federated', '/feed/federated', [Feeds::class, 'federated']);
|
||||
|
||||
$m->connect('freenetwork_hostmeta', '.well-known/host-meta', [HostMeta::class, 'handle']);
|
||||
$m->connect(
|
||||
'freenetwork_hostmeta_format',
|
||||
'.well-known/host-meta.:format',
|
||||
[HostMeta::class, 'handle'],
|
||||
['format' => '(xml|json)'],
|
||||
);
|
||||
// the resource GET parameter can be anywhere, so don't mention it here
|
||||
$m->connect('freenetwork_webfinger', '.well-known/webfinger', [Webfinger::class, 'handle']);
|
||||
$m->connect(
|
||||
'freenetwork_webfinger_format',
|
||||
'.well-known/webfinger.:format',
|
||||
[Webfinger::class, 'handle'],
|
||||
['format' => '(xml|json)'],
|
||||
);
|
||||
$m->connect('freenetwork_ownerxrd', 'main/ownerxrd', [OwnerXrd::class, 'handle']);
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onCreateDefaultFeeds(int $actor_id, LocalUser $user, int &$ordering)
|
||||
{
|
||||
DB::persist(\App\Entity\Feed::create(['actor_id' => $actor_id, 'url' => Router::url($route = 'feed_network'), 'route' => $route, 'title' => _m('Meteorites'), 'ordering' => $ordering++]));
|
||||
DB::persist(\App\Entity\Feed::create(['actor_id' => $actor_id, 'url' => Router::url($route = 'feed_clique'), 'route' => $route, 'title' => _m('Planetary System'), 'ordering' => $ordering++]));
|
||||
DB::persist(\App\Entity\Feed::create(['actor_id' => $actor_id, 'url' => Router::url($route = 'feed_federated'), 'route' => $route, 'title' => _m('Galaxy'), 'ordering' => $ordering++]));
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onStartGetProfileAcctUri(Actor $profile, &$acct): bool
|
||||
{
|
||||
$wfr = new WebFingerResourceActor($profile);
|
||||
try {
|
||||
$acct = $wfr->reconstructAcct();
|
||||
} catch (Exception) {
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
return Event::stop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Last attempts getting a WebFingerResource object
|
||||
*
|
||||
* @param string $resource String that contains the requested URI
|
||||
* @param null|WebfingerResource $target WebFingerResource extended object goes here
|
||||
* @param array $args Array which may contains arguments such as 'rel' filtering values
|
||||
*
|
||||
* @throws NicknameEmptyException
|
||||
* @throws NicknameException
|
||||
* @throws NicknameInvalidException
|
||||
* @throws NicknameNotAllowedException
|
||||
* @throws NicknameTakenException
|
||||
* @throws NicknameTooLongException
|
||||
* @throws NoSuchActorException
|
||||
* @throws ServerException
|
||||
*/
|
||||
public function onEndGetWebFingerResource(string $resource, ?WebfingerResource &$target = null, array $args = []): bool
|
||||
{
|
||||
// * Either we didn't find the profile, then we want to make
|
||||
// the $profile variable null for clarity.
|
||||
// * Or we did find it but for a possibly malicious remote
|
||||
// user who might've set their profile URL to a Note URL
|
||||
// which would've caused a sort of DoS unless we continue
|
||||
// our search here by discarding the remote profile.
|
||||
$profile = null;
|
||||
if (Discovery::isAcct($resource)) {
|
||||
$parts = explode('@', mb_substr(urldecode($resource), 5)); // 5 is strlen of 'acct:'
|
||||
if (\count($parts) === 2) {
|
||||
[$nick, $domain] = $parts;
|
||||
if ($domain !== $_ENV['SOCIAL_DOMAIN']) {
|
||||
throw new ServerException(_m('Remote profiles not supported via WebFinger yet.'));
|
||||
}
|
||||
|
||||
$nick = Nickname::normalize(nickname: $nick, check_already_used: false, check_is_allowed: false);
|
||||
$freenetwork_actor = LocalUser::getByPK(['nickname' => $nick]);
|
||||
if (!($freenetwork_actor instanceof LocalUser)) {
|
||||
throw new NoSuchActorException($nick);
|
||||
}
|
||||
$profile = $freenetwork_actor->getActor();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (Common::isValidHttpUrl($resource)) {
|
||||
// This means $resource is a valid url
|
||||
$resource_parts = parse_url($resource);
|
||||
// TODO: Use URLMatcher
|
||||
if ($resource_parts['host'] === $_ENV['SOCIAL_DOMAIN']) { // XXX: Common::config('site', 'server')) {
|
||||
$str = $resource_parts['path'];
|
||||
// actor_view_nickname
|
||||
$renick = '/\/@(' . Nickname::DISPLAY_FMT . ')\/?/m';
|
||||
// actor_view_id
|
||||
$reuri = '/\/actor\/(\d+)\/?/m';
|
||||
if (preg_match_all($renick, $str, $matches, PREG_SET_ORDER, 0) === 1) {
|
||||
$profile = LocalUser::getByPK(['nickname' => $matches[0][1]])->getActor();
|
||||
} elseif (preg_match_all($reuri, $str, $matches, PREG_SET_ORDER, 0) === 1) {
|
||||
$profile = Actor::getById((int) $matches[0][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoSuchActorException $e) {
|
||||
// not a User, maybe a Note? we'll try that further down...
|
||||
|
||||
// try {
|
||||
// Log::debug(__METHOD__ . ': Finding User_group URI for WebFinger lookup on resource==' . $resource);
|
||||
// $group = new User_group();
|
||||
// $group->whereAddIn('uri', array_keys($alt_urls), $group->columnType('uri'));
|
||||
// $group->limit(1);
|
||||
// if ($group->find(true)) {
|
||||
// $profile = $group->getProfile();
|
||||
// }
|
||||
// unset($group);
|
||||
// } catch (Exception $e) {
|
||||
// Log::error(get_class($e) . ': ' . $e->getMessage());
|
||||
// throw $e;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
if ($profile instanceof Actor) {
|
||||
Log::debug(__METHOD__ . ': Found Profile with ID==' . $profile->getID() . ' for resource==' . $resource);
|
||||
$target = new WebfingerResourceActor($profile);
|
||||
return Event::stop; // We got our target, stop handler execution
|
||||
}
|
||||
|
||||
$APNote = ActivitypubActivity::getByPK(['object_uri' => $resource]);
|
||||
if ($APNote instanceof ActivitypubActivity) {
|
||||
$target = new WebfingerResourceNote(Note::getByPK(['id' => $APNote->getObjectId()]));
|
||||
return Event::stop; // We got our target, stop handler execution
|
||||
}
|
||||
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onStartHostMetaLinks(array &$links): bool
|
||||
{
|
||||
foreach (Discovery::supportedMimeTypes() as $type) {
|
||||
$links[] = new XML_XRD_Element_Link(
|
||||
Discovery::LRDD_REL,
|
||||
Router::url(id: 'freenetwork_webfinger', args: [], type: Router::ABSOLUTE_URL) . '?resource={uri}',
|
||||
$type,
|
||||
isTemplate: true,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO OAuth connections
|
||||
//$links[] = new XML_XRD_Element_link(self::OAUTH_ACCESS_TOKEN_REL, common_local_url('ApiOAuthAccessToken'));
|
||||
//$links[] = new XML_XRD_Element_link(self::OAUTH_REQUEST_TOKEN_REL, common_local_url('ApiOAuthRequestToken'));
|
||||
//$links[] = new XML_XRD_Element_link(self::OAUTH_AUTHORIZE_REL, common_local_url('ApiOAuthAuthorize'));
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a link header for LRDD Discovery
|
||||
*/
|
||||
public function onStartShowHTML($action): bool
|
||||
{
|
||||
if ($action instanceof ShowstreamAction) {
|
||||
$resource = $action->getTarget()->getUri();
|
||||
$url = common_local_url('webfinger') . '?resource=' . urlencode($resource);
|
||||
|
||||
foreach ([Discovery::JRD_MIMETYPE, Discovery::XRD_MIMETYPE] as $type) {
|
||||
header('Link: <' . $url . '>; rel="' . Discovery::LRDD_REL . '"; type="' . $type . '"', false);
|
||||
}
|
||||
}
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onStartDiscoveryMethodRegistration(Discovery $disco): bool
|
||||
{
|
||||
$disco->registerMethod('\Component\FreeNetwork\Util\LrddMethod\LrddMethodWebfinger');
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function onEndDiscoveryMethodRegistration(Discovery $disco): bool
|
||||
{
|
||||
$disco->registerMethod('\Component\FreeNetwork\Util\LrddMethod\LrddMethodHostMeta');
|
||||
$disco->registerMethod('\Component\FreeNetwork\Util\LrddMethod\LrddMethodLinkHeader');
|
||||
$disco->registerMethod('\Component\FreeNetwork\Util\LrddMethod\LrddMethodLinkHtml');
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ClientException
|
||||
* @throws ServerException
|
||||
*/
|
||||
public function onControllerResponseInFormat(string $route, array $accept_header, array $vars, ?TypeResponse &$response = null): bool
|
||||
{
|
||||
if (!\in_array($route, ['freenetwork_hostmeta', 'freenetwork_hostmeta_format', 'freenetwork_webfinger', 'freenetwork_webfinger_format', 'freenetwork_ownerxrd'])) {
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
$mimeType = array_intersect(array_values(Discovery::supportedMimeTypes()), $accept_header);
|
||||
/*
|
||||
* "A WebFinger resource MUST return a JRD as the representation
|
||||
* for the resource if the client requests no other supported
|
||||
* format explicitly via the HTTP "Accept" header. [...]
|
||||
* The WebFinger resource MUST silently ignore any requested
|
||||
* representations that it does not understand and support."
|
||||
* -- RFC 7033 (WebFinger)
|
||||
* http://tools.ietf.org/html/rfc7033
|
||||
*/
|
||||
$mimeType = \count($mimeType) !== 0 ? array_pop($mimeType) : $vars['default_mimetype'];
|
||||
|
||||
$headers = [];
|
||||
|
||||
if (Common::config('discovery', 'cors')) {
|
||||
$headers['Access-Control-Allow-Origin'] = '*';
|
||||
}
|
||||
|
||||
$headers['Content-Type'] = $mimeType;
|
||||
|
||||
$response = match ($mimeType) {
|
||||
Discovery::XRD_MIMETYPE => new Response(content: $vars['xrd']->to('xml'), headers: $headers),
|
||||
Discovery::JRD_MIMETYPE, Discovery::JRD_MIMETYPE_OLD => new JsonResponse(data: $vars['xrd']->to('json'), headers: $headers, json: true),
|
||||
};
|
||||
return Event::stop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Webfinger matches: @user@example.com or even @user--one.george_orwell@1984.biz
|
||||
*
|
||||
* @param string $text The text from which to extract webfinger IDs
|
||||
* @param string $preMention Character(s) that signals a mention ('@', '!'...)
|
||||
*
|
||||
* @return array the matching IDs (without $preMention) and each respective position in the given string
|
||||
*/
|
||||
public static function extractWebfingerIds(string $text, string $preMention = '@'): array
|
||||
{
|
||||
$wmatches = [];
|
||||
$result = preg_match_all(
|
||||
'/' . Nickname::BEFORE_MENTIONS . preg_quote($preMention, '/') . '(' . Nickname::WEBFINGER_FMT . ')/',
|
||||
$text,
|
||||
$wmatches,
|
||||
\PREG_OFFSET_CAPTURE,
|
||||
);
|
||||
if ($result === false) {
|
||||
Log::error(__METHOD__ . ': Error parsing webfinger IDs from text (preg_last_error==' . preg_last_error() . ').');
|
||||
return [];
|
||||
} elseif (($n_matches = \count($wmatches)) != 0) {
|
||||
Log::debug((sprintf('Found %d matches for WebFinger IDs: %s', $n_matches, print_r($wmatches, true))));
|
||||
}
|
||||
return $wmatches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Profile URL matches: @param string $text The text from which to extract URL mentions
|
||||
*
|
||||
* @param string $preMention Character(s) that signals a mention ('@', '!'...)
|
||||
*
|
||||
* @return array the matching URLs (without @ or acct:) and each respective position in the given string
|
||||
* @example.com/mublog/user
|
||||
*/
|
||||
public static function extractUrlMentions(string $text, string $preMention = '@'): array
|
||||
{
|
||||
$wmatches = [];
|
||||
// In the regexp below we need to match / _before_ URL_REGEX_VALID_PATH_CHARS because it otherwise gets merged
|
||||
// with the TLD before (but / is in URL_REGEX_VALID_PATH_CHARS anyway, it's just its positioning that is important)
|
||||
$result = preg_match_all(
|
||||
'/' . Nickname::BEFORE_MENTIONS . preg_quote($preMention, '/') . '(' . URL_REGEX_DOMAIN_NAME . '(?:\/[' . URL_REGEX_VALID_PATH_CHARS . ']*)*)/',
|
||||
$text,
|
||||
$wmatches,
|
||||
\PREG_OFFSET_CAPTURE,
|
||||
);
|
||||
if ($result === false) {
|
||||
Log::error(__METHOD__ . ': Error parsing profile URL mentions from text (preg_last_error==' . preg_last_error() . ').');
|
||||
return [];
|
||||
} elseif (\count($wmatches)) {
|
||||
Log::debug((sprintf('Found %d matches for profile URL mentions: %s', \count($wmatches), print_r($wmatches, true))));
|
||||
}
|
||||
return $wmatches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find any explicit remote mentions. Accepted forms:
|
||||
* Webfinger: @user@example.com
|
||||
* Profile link: @param Actor $sender
|
||||
*
|
||||
* @param string $text input markup text
|
||||
* @param $mentions
|
||||
*
|
||||
* @return bool hook return value
|
||||
* @example.com/mublog/user
|
||||
*/
|
||||
public function onEndFindMentions(Actor $sender, string $text, array &$mentions): bool
|
||||
{
|
||||
$matches = [];
|
||||
|
||||
foreach (self::extractWebfingerIds($text, $preMention = '@') as $wmatch) {
|
||||
[$target, $pos] = $wmatch;
|
||||
Log::info("Checking webfinger person '{$target}'");
|
||||
|
||||
$actor = null;
|
||||
|
||||
$resource_parts = explode($preMention, $target);
|
||||
if ($resource_parts[1] === $_ENV['SOCIAL_DOMAIN']) { // XXX: Common::config('site', 'server')) {
|
||||
$actor = LocalUser::getByPK(['nickname' => $resource_parts[0]])->getActor();
|
||||
} else {
|
||||
Event::handle('FreeNetworkFindMentions', [$target, &$actor]);
|
||||
if (\is_null($actor)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
\assert($actor instanceof Actor);
|
||||
|
||||
$displayName = !empty($actor->getFullname()) ? $actor->getFullname() : $actor->getNickname() ?? $target; // TODO: we could do getBestName() or getFullname() here
|
||||
|
||||
$matches[$pos] = [
|
||||
'mentioned' => [$actor],
|
||||
'type' => 'mention',
|
||||
'text' => $displayName,
|
||||
'position' => $pos,
|
||||
'length' => mb_strlen($target),
|
||||
'url' => $actor->getUri(),
|
||||
];
|
||||
}
|
||||
|
||||
foreach (self::extractUrlMentions($text) as $wmatch) {
|
||||
[$target, $pos] = $wmatch;
|
||||
$url = "https://{$target}";
|
||||
if (Common::isValidHttpUrl($url)) {
|
||||
// This means $resource is a valid url
|
||||
$resource_parts = parse_url($url);
|
||||
// TODO: Use URLMatcher
|
||||
if ($resource_parts['host'] === $_ENV['SOCIAL_DOMAIN']) { // XXX: Common::config('site', 'server')) {
|
||||
$str = $resource_parts['path'];
|
||||
// actor_view_nickname
|
||||
$renick = '/\/@(' . Nickname::DISPLAY_FMT . ')\/?/m';
|
||||
// actor_view_id
|
||||
$reuri = '/\/actor\/(\d+)\/?/m';
|
||||
if (preg_match_all($renick, $str, $matches, PREG_SET_ORDER, 0) === 1) {
|
||||
$actor = LocalUser::getByPK(['nickname' => $matches[0][1]])->getActor();
|
||||
} elseif (preg_match_all($reuri, $str, $matches, PREG_SET_ORDER, 0) === 1) {
|
||||
$actor = Actor::getById((int) $matches[0][1]);
|
||||
} else {
|
||||
Log::error('Unexpected behaviour onEndFindMentions at FreeNetwork');
|
||||
throw new ServerException('Unexpected behaviour onEndFindMentions at FreeNetwork');
|
||||
}
|
||||
} else {
|
||||
Log::info("Checking actor address '{$url}'");
|
||||
|
||||
$link = new XML_XRD_Element_Link(
|
||||
Discovery::LRDD_REL,
|
||||
'https://' . parse_url($url, \PHP_URL_HOST) . '/.well-known/webfinger?resource={uri}',
|
||||
Discovery::JRD_MIMETYPE,
|
||||
true, // isTemplate
|
||||
);
|
||||
$xrd_uri = Discovery::applyTemplate($link->template, $url);
|
||||
$response = HTTPClient::get($xrd_uri, ['headers' => ['Accept' => $link->type]]);
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$xrd = new XML_XRD();
|
||||
|
||||
switch (GSFile::mimetypeBare($response->getHeaders()['content-type'][0])) {
|
||||
case Discovery::JRD_MIMETYPE_OLD:
|
||||
case Discovery::JRD_MIMETYPE:
|
||||
$type = 'json';
|
||||
break;
|
||||
case Discovery::XRD_MIMETYPE:
|
||||
$type = 'xml';
|
||||
break;
|
||||
default:
|
||||
// fall back to letting XML_XRD auto-detect
|
||||
Log::debug('No recognized content-type header for resource descriptor body on ' . $xrd_uri);
|
||||
$type = null;
|
||||
}
|
||||
$xrd->loadString($response->getContent(), $type);
|
||||
|
||||
$actor = null;
|
||||
Event::handle('FreeNetworkFoundXrd', [$xrd, &$actor]);
|
||||
if (\is_null($actor)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$displayName = $actor->getFullname() ?? $actor->getNickname() ?? $target; // TODO: we could do getBestName() or getFullname() here
|
||||
$matches[$pos] = [
|
||||
'mentioned' => [$actor],
|
||||
'type' => 'mention',
|
||||
'text' => $displayName,
|
||||
'position' => $pos,
|
||||
'length' => mb_strlen($target),
|
||||
'url' => $actor->getUri(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($mentions as $i => $other) {
|
||||
// If we share a common prefix with a local user, override it!
|
||||
$pos = $other['position'];
|
||||
if (isset($matches[$pos])) {
|
||||
$mentions[$i] = $matches[$pos];
|
||||
unset($matches[$pos]);
|
||||
}
|
||||
}
|
||||
foreach ($matches as $mention) {
|
||||
$mentions[] = $mention;
|
||||
}
|
||||
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public static function notify(Actor $sender, Activity $activity, array $targets, ?string $reason = null): bool
|
||||
{
|
||||
$protocols = [];
|
||||
Event::handle('AddFreeNetworkProtocol', [&$protocols]);
|
||||
$delivered = [];
|
||||
foreach ($protocols as $protocol) {
|
||||
$protocol::freeNetworkDistribute($sender, $activity, $targets, $reason, $delivered);
|
||||
}
|
||||
$failed_targets = array_udiff($targets, $delivered, fn (Actor $a, Actor $b): int => $a->getId() <=> $b->getId());
|
||||
// TODO: Implement failed queues
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onPluginVersion(array &$versions): bool
|
||||
{
|
||||
$versions[] = [
|
||||
'name' => 'WebFinger',
|
||||
'version' => self::PLUGIN_VERSION,
|
||||
'author' => 'Mikael Nordfeldth',
|
||||
'homepage' => GNUSOCIAL_ENGINE_URL,
|
||||
// TRANS: Plugin description.
|
||||
'rawdescription' => _m('WebFinger and LRDD support'),
|
||||
];
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
The FreeNetwork component adds WebFinger (RFC7033) lookup and implements Link-based Resource Descriptor Discovery (LRDD)
|
||||
based on RFC6415, Web Host Metadata.
|
@@ -1,226 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* This class performs lookups based on methods implemented in separate
|
||||
* classes, where a resource uri is given. Examples are WebFinger (RFC7033)
|
||||
* and the LRDD (Link-based Resource Descriptor Discovery) in RFC6415.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Discovery
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
*
|
||||
* @see http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
namespace Component\FreeNetwork\Util;
|
||||
|
||||
use App\Core\Event;
|
||||
use App\Core\GSFile;
|
||||
use App\Core\HTTPClient;
|
||||
use function App\Core\I18n\_m;
|
||||
use App\Core\Log;
|
||||
use App\Util\Exception\ClientException;
|
||||
use Exception;
|
||||
use XML_XRD;
|
||||
use XML_XRD_Element_Link;
|
||||
|
||||
class Discovery
|
||||
{
|
||||
public const LRDD_REL = 'lrdd';
|
||||
public const UPDATESFROM = 'http://schemas.google.com/g/2010#updates-from';
|
||||
public const HCARD = 'http://microformats.org/profile/hcard';
|
||||
public const MF2_HCARD = 'http://microformats.org/profile/h-card'; // microformats2 h-card
|
||||
|
||||
public const JRD_MIMETYPE_OLD = 'application/json'; // RFC6415 uses this
|
||||
public const JRD_MIMETYPE = 'application/jrd+json';
|
||||
public const XRD_MIMETYPE = 'application/xrd+xml';
|
||||
|
||||
public array $methods = [];
|
||||
|
||||
/**
|
||||
* Constructor for a discovery object
|
||||
*
|
||||
* Registers different discovery methods.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (Event::handle('StartDiscoveryMethodRegistration', [$this])) {
|
||||
Event::handle('EndDiscoveryMethodRegistration', [$this]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function supportedMimeTypes(): array
|
||||
{
|
||||
return [
|
||||
'json' => self::JRD_MIMETYPE,
|
||||
'jsonold' => self::JRD_MIMETYPE_OLD,
|
||||
'xml' => self::XRD_MIMETYPE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a discovery class
|
||||
*
|
||||
* @param string $class Class name
|
||||
*/
|
||||
public function registerMethod($class): void
|
||||
{
|
||||
$this->methods[] = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user ID, return the first available resource descriptor
|
||||
*
|
||||
* @param string $id User ID URI
|
||||
*
|
||||
* @return XML_XRD object for the resource descriptor of the id
|
||||
*/
|
||||
public function lookup(string $id): XML_XRD
|
||||
{
|
||||
// Normalize the incoming $id to make sure we have an uri
|
||||
$uri = self::normalize($id);
|
||||
|
||||
Log::debug(sprintf('Performing discovery for "%s" (normalized "%s")', $id, $uri));
|
||||
|
||||
foreach ($this->methods as $class) {
|
||||
try {
|
||||
$xrd = new XML_XRD();
|
||||
|
||||
Log::debug("LRDD discovery method for '{$uri}': {$class}");
|
||||
$lrdd = new $class;
|
||||
$links = $lrdd->discover($uri);
|
||||
$link = self::getService($links, self::LRDD_REL);
|
||||
|
||||
// Load the LRDD XRD
|
||||
if (!empty($link->template)) {
|
||||
$xrd_uri = self::applyTemplate($link->template, $uri);
|
||||
} elseif (!empty($link->href)) {
|
||||
$xrd_uri = $link->href;
|
||||
} else {
|
||||
throw new Exception('No resource descriptor URI in link.');
|
||||
}
|
||||
|
||||
$headers = [];
|
||||
if (!\is_null($link->type)) {
|
||||
$headers['Accept'] = $link->type;
|
||||
}
|
||||
|
||||
$response = HTTPClient::get($xrd_uri, ['headers' => $headers]);
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new Exception('Unexpected HTTP status code.');
|
||||
}
|
||||
|
||||
switch (GSFile::mimetypeBare($response->getHeaders()['content-type'][0])) {
|
||||
case self::JRD_MIMETYPE_OLD:
|
||||
case self::JRD_MIMETYPE:
|
||||
$type = 'json';
|
||||
break;
|
||||
case self::XRD_MIMETYPE:
|
||||
$type = 'xml';
|
||||
break;
|
||||
default:
|
||||
// fall back to letting XML_XRD auto-detect
|
||||
Log::debug('No recognized content-type header for resource descriptor body on ' . $xrd_uri);
|
||||
$type = null;
|
||||
}
|
||||
$xrd->loadString($response->getContent(), $type);
|
||||
return $xrd;
|
||||
} catch (ClientException $e) {
|
||||
if ($e->getCode() === 403) {
|
||||
Log::info(sprintf('%s: Aborting discovery on URL %s: %s', $class, $uri, $e->getMessage()));
|
||||
break;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Log::info(sprintf('%s: Failed for %s: %s', $class, $uri, $e->getMessage()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// TRANS: Exception. %s is an ID.
|
||||
throw new Exception(sprintf(_m('Unable to find services for %s.'), $id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of links, returns the matching service
|
||||
*
|
||||
* @param array $links Links to check (as instances of XML_XRD_Element_Link)
|
||||
* @param string $service Service to find
|
||||
*
|
||||
* @return XML_XRD_Element_Link $link
|
||||
*/
|
||||
public static function getService(array $links, $service): XML_XRD_Element_Link
|
||||
{
|
||||
foreach ($links as $link) {
|
||||
if ($link->rel === $service) {
|
||||
return $link;
|
||||
}
|
||||
Log::debug('LINK: rel ' . $link->rel . ' !== ' . $service);
|
||||
}
|
||||
|
||||
throw new Exception('No service link found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a "user id" make sure it's normalized to an acct: uri
|
||||
*
|
||||
* @param string $uri User ID to normalize
|
||||
*
|
||||
* @return string normalized acct: URI
|
||||
*/
|
||||
public static function normalize(string $uri): string
|
||||
{
|
||||
$parts = parse_url($uri);
|
||||
// If we don't have a scheme, but the path implies user@host,
|
||||
// though this is far from a perfect matching procedure...
|
||||
if (!isset($parts['scheme']) && isset($parts['path'])
|
||||
&& preg_match('/[\w@\w]/u', $parts['path'])) {
|
||||
return 'acct:' . $uri;
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public static function isAcct(string $uri): bool
|
||||
{
|
||||
return mb_strtolower(mb_substr($uri, 0, 5)) == 'acct:';
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a template using an ID
|
||||
*
|
||||
* Replaces {uri} in template string with the ID given.
|
||||
*
|
||||
* @param string $template Template to match
|
||||
* @param string $uri URI to replace with
|
||||
*
|
||||
* @return string replaced values
|
||||
*/
|
||||
public static function applyTemplate($template, $uri): string
|
||||
{
|
||||
return str_replace('{uri}', urlencode($uri), $template);
|
||||
}
|
||||
}
|
@@ -1,127 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* Parse HTTP response for interesting Link: headers
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Discovery
|
||||
* @package StatusNet
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
*
|
||||
* @see http://status.net/
|
||||
*/
|
||||
|
||||
namespace Component\FreeNetwork\Util;
|
||||
|
||||
/**
|
||||
* Class to represent Link: headers in an HTTP response
|
||||
*
|
||||
* Since these are a fairly important part of Hammer-stack discovery, they're
|
||||
* reified and implemented here.
|
||||
*
|
||||
* @category Discovery
|
||||
* @package StatusNet
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
*
|
||||
* @see http://status.net/
|
||||
* @see Discovery
|
||||
*/
|
||||
class LinkHeader
|
||||
{
|
||||
public $href;
|
||||
public $rel;
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* Initialize from a string
|
||||
*
|
||||
* @param string $str Link: header value
|
||||
*/
|
||||
public function __construct(string $str = '')
|
||||
{
|
||||
preg_match('/^<[^>]+>/', $str, $uri_reference);
|
||||
//if (empty($uri_reference)) return;
|
||||
|
||||
$this->href = trim($uri_reference[0], '<>');
|
||||
$this->rel = [];
|
||||
$this->type = null;
|
||||
|
||||
// remove uri-reference from header
|
||||
$str = substr($str, strlen($uri_reference[0]));
|
||||
|
||||
// parse link-params
|
||||
$params = explode(';', $str);
|
||||
|
||||
foreach ($params as $param) {
|
||||
if (empty($param)) {
|
||||
continue;
|
||||
}
|
||||
list($param_name, $param_value) = explode('=', $param, 2);
|
||||
|
||||
$param_name = trim($param_name);
|
||||
$param_value = preg_replace('(^"|"$)', '', trim($param_value));
|
||||
|
||||
// for now we only care about 'rel' and 'type' link params
|
||||
// TODO do something with the other links-params
|
||||
switch ($param_name) {
|
||||
case 'rel':
|
||||
$this->rel = trim($param_value);
|
||||
break;
|
||||
|
||||
case 'type':
|
||||
$this->type = trim($param_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an HTTP response, return the requested Link: header
|
||||
*
|
||||
* @param HTTP_Request2_Response $response response to check
|
||||
* @param string $rel relationship to look for
|
||||
* @param string $type media type to look for
|
||||
*
|
||||
* @return LinkHeader discovered header, or null on failure
|
||||
*/
|
||||
public static function getLink($response, $rel = null, $type = null)
|
||||
{
|
||||
$headers = $response->getHeader('Link');
|
||||
if ($headers) {
|
||||
// Can get an array or string, so try to simplify the path
|
||||
if (!is_array($headers)) {
|
||||
$headers = [$headers];
|
||||
}
|
||||
|
||||
foreach ($headers as $header) {
|
||||
$lh = new self($header);
|
||||
|
||||
if ((is_null($rel) || $lh->rel == $rel) && (is_null($type) || $lh->type == $type)) {
|
||||
return $lh->href;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Component\FreeNetwork\Util;
|
||||
|
||||
use App\Core\Event;
|
||||
use App\Core\HTTPClient;
|
||||
use Exception;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use XML_XRD;
|
||||
|
||||
/**
|
||||
* Abstract class for LRDD discovery methods
|
||||
*
|
||||
* Objects that extend this class can retrieve an array of
|
||||
* resource descriptor links for the URI. The array consists
|
||||
* of XML_XRD_Element_Link elements.
|
||||
*
|
||||
* @category Discovery
|
||||
* @package StatusNet
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
*
|
||||
* @see http://status.net/
|
||||
*/
|
||||
abstract class LrddMethod
|
||||
{
|
||||
protected $xrd;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->xrd = new XML_XRD();
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover interesting info about the URI
|
||||
*
|
||||
* @param string $uri URI to inquire about
|
||||
*
|
||||
* @return array of XML_XRD_Element_Link elements to discovered resource descriptors
|
||||
*/
|
||||
abstract public function discover($uri);
|
||||
|
||||
protected function fetchUrl($url, $method = 'get'): ResponseInterface
|
||||
{
|
||||
// If we have a blacklist enabled, let's check against it
|
||||
Event::handle('UrlBlacklistTest', [$url]);
|
||||
|
||||
$response = HTTPClient::$method($url);
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new Exception('Unexpected HTTP status code.');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Component\FreeNetwork\Util\LrddMethod;
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
use App\Core\Log;
|
||||
use Component\FreeNetwork\Util\Discovery;
|
||||
use Component\FreeNetwork\Util\LrddMethod;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Implementation of discovery using host-meta file
|
||||
*
|
||||
* Discovers resource descriptor file for a user by going to the
|
||||
* organization's host-meta file and trying to find a template for LRDD.
|
||||
*
|
||||
* @category Discovery
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class LrddMethodHostMeta extends LRDDMethod
|
||||
{
|
||||
/**
|
||||
* For RFC6415 and HTTP URIs, fetch the host-meta file
|
||||
* and look for LRDD templates
|
||||
*
|
||||
* @param mixed $uri
|
||||
*/
|
||||
public function discover($uri)
|
||||
{
|
||||
// This is allowed for RFC6415 but not the 'WebFinger' RFC7033.
|
||||
$try_schemes = ['https', 'http'];
|
||||
|
||||
$scheme = mb_strtolower(parse_url($uri, PHP_URL_SCHEME));
|
||||
switch ($scheme) {
|
||||
case 'acct':
|
||||
// We can't use parse_url data for this, since the 'host'
|
||||
// entry is only set if the scheme has '://' after it.
|
||||
$parts = explode('@', parse_url($uri, PHP_URL_PATH), 2);
|
||||
|
||||
if (!Discovery::isAcct($uri) || count($parts) != 2) {
|
||||
throw new Exception('Bad resource URI: ' . $uri);
|
||||
}
|
||||
[, $domain] = $parts;
|
||||
break;
|
||||
case 'http':
|
||||
case 'https':
|
||||
$domain = mb_strtolower(parse_url($uri, PHP_URL_HOST));
|
||||
$try_schemes = [$scheme];
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Unable to discover resource descriptor endpoint.');
|
||||
}
|
||||
|
||||
foreach ($try_schemes as $scheme) {
|
||||
$url = $scheme . '://' . $domain . '/.well-known/host-meta';
|
||||
|
||||
try {
|
||||
$response = self::fetchUrl($url);
|
||||
$this->xrd->loadString($response->getContent());
|
||||
} catch (Exception $e) {
|
||||
Log::debug('LRDD could not load resource descriptor: ' . $url . ' (' . $e->getMessage() . ')');
|
||||
continue;
|
||||
}
|
||||
return $this->xrd->links;
|
||||
}
|
||||
|
||||
throw new Exception('Unable to retrieve resource descriptor links.');
|
||||
}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Component\FreeNetwork\Util\LrddMethod;
|
||||
|
||||
use App\Core\Log;
|
||||
use Component\FreeNetwork\Util\LinkHeader;
|
||||
use Component\FreeNetwork\Util\LrddMethod;
|
||||
use Exception;
|
||||
use XML_XRD_Element_Link;
|
||||
|
||||
/**
|
||||
* Implementation of discovery using HTTP Link header
|
||||
*
|
||||
* Discovers XRD file for a user by fetching the URL and reading any
|
||||
* Link: headers in the HTTP response.
|
||||
*
|
||||
* @category Discovery
|
||||
* @package StatusNet
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
*
|
||||
* @see http://status.net/
|
||||
*/
|
||||
class LrddMethodLinkHeader extends LRDDMethod
|
||||
{
|
||||
/**
|
||||
* For HTTP IDs fetch the URL and look for Link headers.
|
||||
*
|
||||
* @todo fail out of WebFinger URIs faster
|
||||
*/
|
||||
public function discover($uri)
|
||||
{
|
||||
$response = self::fetchUrl($uri, 'head');
|
||||
|
||||
$link_header = $response->getHeaders()['link'][0];
|
||||
if (empty($link_header)) {
|
||||
throw new Exception('No Link header found');
|
||||
}
|
||||
Log::debug('LRDD LinkHeader found: ' . var_export($link_header, true));
|
||||
|
||||
return self::parseHeader($link_header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a string or array of headers, returns JRD-like assoc array
|
||||
*
|
||||
* @param array|string $header string or array of strings for headers
|
||||
*
|
||||
* @return array of associative arrays in JRD-like array format
|
||||
*/
|
||||
protected static function parseHeader($header)
|
||||
{
|
||||
$lh = new LinkHeader($header);
|
||||
|
||||
$link = new XML_XRD_Element_Link($lh->rel, $lh->href, $lh->type);
|
||||
|
||||
return [$link];
|
||||
}
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Component\FreeNetwork\Util\LrddMethod;
|
||||
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
use Component\FreeNetwork\Util\LrddMethod;
|
||||
use XML_XRD_Element_Link;
|
||||
|
||||
/**
|
||||
* Implementation of discovery using HTML <link> element
|
||||
*
|
||||
* Discovers XRD file for a user by fetching the URL and reading any
|
||||
* <link> elements in the HTML response.
|
||||
*
|
||||
* @category Discovery
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author James Walker <james@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class LrddMethodLinkHtml extends LRDDMethod
|
||||
{
|
||||
/**
|
||||
* For HTTP IDs, fetch the URL and look for <link> elements
|
||||
* in the HTML response.
|
||||
*
|
||||
* @param mixed $uri
|
||||
*
|
||||
* @todo fail out of WebFinger URIs faster
|
||||
*
|
||||
*/
|
||||
public function discover($uri)
|
||||
{
|
||||
$response = self::fetchUrl($uri);
|
||||
|
||||
return self::parse($response->getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse HTML and return <link> elements
|
||||
*
|
||||
* Given an HTML string, scans the string for <link> elements
|
||||
*
|
||||
* @param string $html HTML to scan
|
||||
*
|
||||
* @return array array of associative arrays in JRD-ish array format
|
||||
*/
|
||||
public function parse($html)
|
||||
{
|
||||
$links = [];
|
||||
|
||||
preg_match('/<head(\s[^>]*)?>(.*?)<\/head>/is', $html, $head_matches);
|
||||
|
||||
if (count($head_matches) != 3) {
|
||||
return [];
|
||||
}
|
||||
[, , $head_html] = $head_matches;
|
||||
|
||||
preg_match_all('/<link\s[^>]*>/i', $head_html, $link_matches);
|
||||
|
||||
foreach ($link_matches[0] as $link_html) {
|
||||
$link_url = null;
|
||||
$link_rel = null;
|
||||
$link_type = null;
|
||||
|
||||
preg_match('/\srel=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $rel_matches);
|
||||
if (count($rel_matches) > 3) {
|
||||
$link_rel = $rel_matches[3];
|
||||
} elseif (count($rel_matches) > 1) {
|
||||
$link_rel = $rel_matches[1];
|
||||
}
|
||||
|
||||
preg_match('/\shref=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $href_matches);
|
||||
if (count($href_matches) > 3) {
|
||||
$link_uri = $href_matches[3];
|
||||
} elseif (count($href_matches) > 1) {
|
||||
$link_uri = $href_matches[1];
|
||||
}
|
||||
|
||||
preg_match('/\stype=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $type_matches);
|
||||
if (count($type_matches) > 3) {
|
||||
$link_type = $type_matches[3];
|
||||
} elseif (count($type_matches) > 1) {
|
||||
$link_type = $type_matches[1];
|
||||
}
|
||||
|
||||
$links[] = new XML_XRD_Element_Link($link_rel, $link_uri, $link_type);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Component\FreeNetwork\Util\LrddMethod;
|
||||
|
||||
use Component\FreeNetwork\Util\Discovery;
|
||||
use Component\FreeNetwork\Util\LrddMethod;
|
||||
use Exception;
|
||||
use XML_XRD_Element_Link;
|
||||
|
||||
/**
|
||||
* Implementation of WebFinger resource discovery (RFC7033)
|
||||
*
|
||||
* @category Discovery
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2013 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class LrddMethodWebfinger extends LRDDMethod
|
||||
{
|
||||
/**
|
||||
* Simply returns the WebFinger URL over HTTPS at the uri's domain:
|
||||
* https://{domain}/.well-known/webfinger?resource={uri}
|
||||
*
|
||||
* @param mixed $uri
|
||||
*/
|
||||
public function discover($uri)
|
||||
{
|
||||
$parts = explode('@', parse_url($uri, PHP_URL_PATH), 2);
|
||||
|
||||
if (!Discovery::isAcct($uri) || count($parts) != 2) {
|
||||
throw new Exception('Bad resource URI: ' . $uri);
|
||||
}
|
||||
[, $domain] = $parts;
|
||||
if (!filter_var($domain, FILTER_VALIDATE_IP)
|
||||
&& !filter_var(gethostbyname($domain), FILTER_VALIDATE_IP)) {
|
||||
throw new Exception('Bad resource host.');
|
||||
}
|
||||
|
||||
$link = new XML_XRD_Element_Link(
|
||||
Discovery::LRDD_REL,
|
||||
'https://' . $domain . '/.well-known/webfinger?resource={uri}',
|
||||
Discovery::JRD_MIMETYPE,
|
||||
true // isTemplate
|
||||
);
|
||||
|
||||
return [$link];
|
||||
}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Component\FreeNetwork\Util;
|
||||
|
||||
use App\Core\Entity;
|
||||
use App\Util\Common;
|
||||
use App\Util\Exception\ServerException;
|
||||
use XML_XRD;
|
||||
|
||||
/**
|
||||
* WebFinger resource parent class
|
||||
*
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author Mikael Nordfeldth
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
*
|
||||
* @see http://status.net/
|
||||
*/
|
||||
abstract class WebfingerResource
|
||||
{
|
||||
protected $identities = [];
|
||||
|
||||
protected $object;
|
||||
protected $type;
|
||||
|
||||
public function __construct(Entity $object)
|
||||
{
|
||||
$this->object = $object;
|
||||
}
|
||||
|
||||
public function getObject()
|
||||
{
|
||||
if ($this->object === null) {
|
||||
throw new ServerException('Object is not set');
|
||||
}
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of alternative IDs of a certain Actor
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAliases(): array
|
||||
{
|
||||
$aliases = $this->object->getAliasesWithIDs();
|
||||
|
||||
// Some sites have changed from http to https and still want
|
||||
// (because remote sites look for it) verify that they are still
|
||||
// the same identity as they were on HTTP. Should NOT be used if
|
||||
// you've run HTTPS all the time!
|
||||
if (Common::config('fix', 'legacy_http')) {
|
||||
foreach ($aliases as $alias => $id) {
|
||||
if (!strtolower(parse_url($alias, PHP_URL_SCHEME)) === 'https') {
|
||||
continue;
|
||||
}
|
||||
$aliases[preg_replace('/^https:/i', 'http:', $alias, 1)] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
// return a unique set of aliases by extracting only the keys
|
||||
return array_keys($aliases);
|
||||
}
|
||||
|
||||
abstract public function updateXRD(XML_XRD $xrd);
|
||||
}
|
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Component\FreeNetwork\Util\WebfingerResource;
|
||||
|
||||
use App\Core\Event;
|
||||
use App\Core\Log;
|
||||
use App\Core\Router\Router;
|
||||
use App\Entity\Actor;
|
||||
use App\Util\Common;
|
||||
use Component\FreeNetwork\Exception\WebfingerReconstructionException;
|
||||
use Component\FreeNetwork\Util\WebfingerResource;
|
||||
use XML_XRD;
|
||||
use XML_XRD_Element_Link;
|
||||
|
||||
/**
|
||||
* WebFinger resource for Profile objects
|
||||
*
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author Mikael Nordfeldth
|
||||
* @author Diogo Peralta Cordeiro
|
||||
* @copyright 2013, 2021 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
*/
|
||||
class WebfingerResourceActor extends WebFingerResource
|
||||
{
|
||||
const PROFILEPAGE = 'http://webfinger.net/rel/profile-page';
|
||||
|
||||
public function __construct(Actor $object = null)
|
||||
{
|
||||
// The type argument above verifies that it's our class
|
||||
parent::__construct($object);
|
||||
}
|
||||
|
||||
public function getAliases(): array
|
||||
{
|
||||
$aliases = [];
|
||||
|
||||
try {
|
||||
// Try to create an acct: URI if we're dealing with a profile
|
||||
$aliases[] = $this->reconstructAcct();
|
||||
} catch (WebFingerReconstructionException $e) {
|
||||
Log::debug("WebFinger reconstruction for Profile failed (id={$this->object->getID()})");
|
||||
}
|
||||
|
||||
return array_merge($aliases, parent::getAliases());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstruct WebFinger acct: from object
|
||||
*
|
||||
* @return array|false|mixed|string|string[]|null
|
||||
* @throws WebfingerReconstructionException
|
||||
*/
|
||||
public function reconstructAcct()
|
||||
{
|
||||
$acct = null;
|
||||
|
||||
if (Event::handle('StartWebFingerReconstruction', [$this->object, &$acct])) {
|
||||
// TODO: getUri may not always give us the correct host on remote users?
|
||||
$host = parse_url($this->object->getUri(Router::ABSOLUTE_URL), PHP_URL_HOST);
|
||||
if (empty($this->object->getNickname()) || empty($host)) {
|
||||
throw new WebFingerReconstructionException(print_r($this->object, true));
|
||||
}
|
||||
$acct = mb_strtolower(sprintf('acct:%s@%s', $this->object->getNickname(), $host));
|
||||
|
||||
Event::handle('EndWebFingerReconstruction', [$this->object, &$acct]);
|
||||
}
|
||||
|
||||
return $acct;
|
||||
}
|
||||
|
||||
public function updateXRD(XML_XRD $xrd)
|
||||
{
|
||||
if (Event::handle('StartWebFingerProfileLinks', [$xrd, $this->object])) {
|
||||
|
||||
// Profile page, can give more metadata from Link header or HTML parsing
|
||||
$xrd->links[] = new XML_XRD_Element_Link(self::PROFILEPAGE,
|
||||
$this->object->getUrl(Router::ABSOLUTE_URL), 'text/html');
|
||||
|
||||
// // XFN
|
||||
// $xrd->links[] = new XML_XRD_Element_Link('http://gmpg.org/xfn/11',
|
||||
// $this->object->getUrl(), 'text/html');
|
||||
// if ($this->object->isPerson()) {
|
||||
// // FOAF for user
|
||||
// $xrd->links[] = new XML_XRD_Element_Link('describedby',
|
||||
// common_local_url('foaf',
|
||||
// ['nickname' => $this->object->getNickname()]),
|
||||
// 'application/rdf+xml');
|
||||
//
|
||||
// // nickname discovery for apps etc.
|
||||
// $link = new XML_XRD_Element_Link('http://apinamespace.org/atom',
|
||||
// common_local_url('ApiAtomService',
|
||||
// ['id' => $this->object->getNickname()]),
|
||||
// 'application/atomsvc+xml');
|
||||
// // XML_XRD must implement changing properties first $link['http://apinamespace.org/atom/username'] = $this->object->getNickname();
|
||||
// $xrd->links[] = clone $link;
|
||||
//
|
||||
// $link = new XML_XRD_Element_Link('http://apinamespace.org/twitter', $apiRoot);
|
||||
// // XML_XRD must implement changing properties first $link['http://apinamespace.org/twitter/username'] = $this->object->getNickname();
|
||||
// $xrd->links[] = clone $link;
|
||||
// } elseif ($this->object->isGroup()) {
|
||||
// // FOAF for group
|
||||
// $xrd->links[] = new XML_XRD_Element_Link('describedby',
|
||||
// common_local_url('foafgroup',
|
||||
// ['nickname' => $this->object->getNickname()]),
|
||||
// 'application/rdf+xml');
|
||||
// }
|
||||
|
||||
Event::handle('EndWebFingerProfileLinks', [$xrd, $this->object]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Component\FreeNetwork\Util\WebfingerResource;
|
||||
|
||||
use App\Core\Event;
|
||||
use App\Entity\Note;
|
||||
use Component\FreeNetwork\Util\WebfingerResource;
|
||||
use PharIo\Manifest\InvalidUrlException;
|
||||
use XML_XRD;
|
||||
use XML_XRD_Element_Link;
|
||||
|
||||
/**
|
||||
* WebFinger resource for Note objects
|
||||
*
|
||||
* @package GNUsocial
|
||||
*
|
||||
* @author Mikael Nordfeldth
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
*
|
||||
* @see http://status.net/
|
||||
*/
|
||||
class WebfingerResourceNote extends WebfingerResource
|
||||
{
|
||||
public function __construct(Note $object = null)
|
||||
{
|
||||
// The type argument above verifies that it's our class
|
||||
parent::__construct($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update given XRD with self's data
|
||||
*
|
||||
* @param XML_XRD $xrd
|
||||
*/
|
||||
public function updateXRD(XML_XRD $xrd)
|
||||
{
|
||||
if (Event::handle('StartWebFingerNoticeLinks', [$xrd, $this->object])) {
|
||||
if ($this->object->isLocal()) {
|
||||
$xrd->links[] = new XML_XRD_Element_Link('alternate',
|
||||
common_local_url('ApiStatusesShow',
|
||||
['id' => $this->object->id,
|
||||
'format' => 'atom', ]),
|
||||
'application/atom+xml');
|
||||
|
||||
$xrd->links[] = new XML_XRD_Element_Link('alternate',
|
||||
common_local_url('ApiStatusesShow',
|
||||
['id' => $this->object->id,
|
||||
'format' => 'json', ]),
|
||||
'application/json');
|
||||
} else {
|
||||
try {
|
||||
$xrd->links[] = new XML_XRD_Element_Link('alternate',
|
||||
$this->object->getUrl(),
|
||||
'text/html');
|
||||
} catch (InvalidUrlException $e) {
|
||||
// don't do a fallback in webfinger
|
||||
}
|
||||
}
|
||||
Event::handle('EndWebFingerNoticeLinks', [$xrd, $this->object]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Component\FreeNetwork\Util;
|
||||
|
||||
use App\Core\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use XML_XRD;
|
||||
|
||||
abstract class XrdController extends Controller
|
||||
{
|
||||
protected string $default_mimetype = Discovery::JRD_MIMETYPE;
|
||||
|
||||
protected XML_XRD $xrd;
|
||||
|
||||
/*
|
||||
* Configures $this->xrd which will later be printed. Must be
|
||||
* implemented by child classes.
|
||||
*/
|
||||
abstract protected function setXRD();
|
||||
|
||||
public function __construct(RequestStack $requestStack)
|
||||
{
|
||||
parent::__construct($requestStack);
|
||||
|
||||
if ($this->request->headers->get('format', null) === null) {
|
||||
$this->request->headers->set('format', $this->default_mimetype);
|
||||
}
|
||||
|
||||
$this->xrd = new XML_XRD();
|
||||
}
|
||||
|
||||
public function handle(Request $request): array
|
||||
{
|
||||
$this->setXRD();
|
||||
return ['xrd' => $this->xrd, 'default_mimetype' => $this->default_mimetype];
|
||||
}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"require": {
|
||||
"pear/xml_xrd": "^0.3.1"
|
||||
}
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-07-18 12:38+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:64
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-07-18 12:38+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:230
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Afrikaans (http://www.transifex.com/gnu-social/gnu-social/language/af/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: af\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Afrikaans (http://www.transifex.com/gnu-social/gnu-social/language/af/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: af\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Arabic (http://www.transifex.com/gnu-social/gnu-social/language/ar/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ar\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Arabic (http://www.transifex.com/gnu-social/gnu-social/language/ar/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ar\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Arabic (Egypt) (http://www.transifex.com/gnu-social/gnu-social/language/ar_EG/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ar_EG\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Arabic (Egypt) (http://www.transifex.com/gnu-social/gnu-social/language/ar_EG/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ar_EG\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Asturian (http://www.transifex.com/gnu-social/gnu-social/language/ast/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ast\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Asturian (http://www.transifex.com/gnu-social/gnu-social/language/ast/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ast\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Belarusian (Tarask) (http://www.transifex.com/gnu-social/gnu-social/language/be@tarask/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: be@tarask\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Belarusian (Tarask) (http://www.transifex.com/gnu-social/gnu-social/language/be@tarask/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: be@tarask\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Bulgarian (http://www.transifex.com/gnu-social/gnu-social/language/bg/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: bg\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Bulgarian (http://www.transifex.com/gnu-social/gnu-social/language/bg/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: bg\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Bengali (India) (http://www.transifex.com/gnu-social/gnu-social/language/bn_IN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: bn_IN\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Bengali (India) (http://www.transifex.com/gnu-social/gnu-social/language/bn_IN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: bn_IN\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Breton (http://www.transifex.com/gnu-social/gnu-social/language/br/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: br\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Breton (http://www.transifex.com/gnu-social/gnu-social/language/br/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: br\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Catalan (http://www.transifex.com/gnu-social/gnu-social/language/ca/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ca\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Catalan (http://www.transifex.com/gnu-social/gnu-social/language/ca/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ca\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Czech (http://www.transifex.com/gnu-social/gnu-social/language/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Czech (http://www.transifex.com/gnu-social/gnu-social/language/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Danish (http://www.transifex.com/gnu-social/gnu-social/language/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: da\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Danish (http://www.transifex.com/gnu-social/gnu-social/language/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: da\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: German (http://www.transifex.com/gnu-social/gnu-social/language/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: German (http://www.transifex.com/gnu-social/gnu-social/language/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Greek (http://www.transifex.com/gnu-social/gnu-social/language/el/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: el\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Greek (http://www.transifex.com/gnu-social/gnu-social/language/el/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: el\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,24 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
# Luke Hollins <luke@farcry.ca>, 2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-03-07 15:41+0000\n"
|
||||
"Last-Translator: Luke Hollins <luke@farcry.ca>\n"
|
||||
"Language-Team: English (United Kingdom) (http://www.transifex.com/gnu-social/gnu-social/language/en_GB/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en_GB\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr "Implements LRDD support for GNU Social."
|
@@ -1,29 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
# Luke Hollins <luke@farcry.ca>, 2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-03-07 13:42+0000\n"
|
||||
"Last-Translator: Luke Hollins <luke@farcry.ca>\n"
|
||||
"Language-Team: English (United Kingdom) (http://www.transifex.com/gnu-social/gnu-social/language/en_GB/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en_GB\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr "Resource not found in local database."
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr "Adds WebFinger lookup to GNU Social"
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Esperanto (http://www.transifex.com/gnu-social/gnu-social/language/eo/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: eo\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Esperanto (http://www.transifex.com/gnu-social/gnu-social/language/eo/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: eo\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,25 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
# Ismael Moral <jastertdc@gmail.com>, 2015
|
||||
# Juan Riquelme González <soulchainer@gmail.com>, 2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-27 15:36+0000\n"
|
||||
"Last-Translator: Juan Riquelme González <soulchainer@gmail.com>\n"
|
||||
"Language-Team: Spanish (http://www.transifex.com/gnu-social/gnu-social/language/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr "Implementa soporte de <abbr title=\"Link-based Resource Descriptor Discovery\">LRDD</abbr> para GNU Social. "
|
@@ -1,30 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
# Ismael Moral <jastertdc@gmail.com>, 2015
|
||||
# Juan Riquelme González <soulchainer@gmail.com>, 2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-28 21:51+0000\n"
|
||||
"Last-Translator: Juan Riquelme González <soulchainer@gmail.com>\n"
|
||||
"Language-Team: Spanish (http://www.transifex.com/gnu-social/gnu-social/language/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr "Recurso no encontrado en la base de datos local. "
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr "Añade búsqueda de WebFinger a GNU social."
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Basque (http://www.transifex.com/gnu-social/gnu-social/language/eu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: eu\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Basque (http://www.transifex.com/gnu-social/gnu-social/language/eu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: eu\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Persian (http://www.transifex.com/gnu-social/gnu-social/language/fa/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fa\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Persian (http://www.transifex.com/gnu-social/gnu-social/language/fa/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fa\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Finnish (http://www.transifex.com/gnu-social/gnu-social/language/fi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fi\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
@@ -1,28 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 12:23+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Finnish (http://www.transifex.com/gnu-social/gnu-social/language/fi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fi\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr ""
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr ""
|
@@ -1,24 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
# iGor milhit <igormilhit@mailoo.org>, 2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-05-06 05:51+0000\n"
|
||||
"Last-Translator: iGor milhit <igormilhit@mailoo.org>\n"
|
||||
"Language-Team: French (http://www.transifex.com/gnu-social/gnu-social/language/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr "Implémente le support LRDD pour GNU Social"
|
@@ -1,30 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
# kris <cb16@actocom.com>, 2015
|
||||
# Vinilox <vinilox@vinilox.eu>, 2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-05-03 19:54+0000\n"
|
||||
"Last-Translator: kris <cb16@actocom.com>\n"
|
||||
"Language-Team: French (http://www.transifex.com/gnu-social/gnu-social/language/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. TRANS: Error message when an object URI which we cannot find was requested
|
||||
#: actions/webfinger.php:49
|
||||
msgid "Resource not found in local database."
|
||||
msgstr "La ressource n'a pas été trouvée dans la base de données"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: WebFingerPlugin.php:147
|
||||
msgid "Adds WebFinger lookup to GNU Social"
|
||||
msgstr "Ajoutez la recherche de webfinger à GNU Social"
|
@@ -1,23 +0,0 @@
|
||||
# Translation file for GNU social - the free software social networking platform
|
||||
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
# This file is under https://www.gnu.org/licenses/agpl v3 or later
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GNU social\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
|
||||
"PO-Revision-Date: 2015-02-07 08:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Friulian (http://www.transifex.com/gnu-social/gnu-social/language/fur/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fur\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. TRANS: Plugin description.
|
||||
#: LRDDPlugin.php:61
|
||||
msgid "Implements LRDD support for GNU Social."
|
||||
msgstr ""
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user