forked from GNUsocial/gnu-social
Compare commits
1589 Commits
v1.20.9rel
...
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 | |||
| b4b71f7626 | |||
| f088a3d54f | |||
| 5b23781e68 | |||
| edc9fd203d | |||
| 844ecbf71e | |||
| 8570ad2094 | |||
| bc3eb7bccc | |||
| 800c0daafe | |||
| 9b1ccdc320 | |||
| 6c8e826028 | |||
| d47bb3736e | |||
| ec1719e61d | |||
| a657a7809a | |||
| ef0f65720e | |||
| 22b5dd8567 | |||
| f9290705f8 | |||
| e51520bd63 | |||
| 6028175bfc | |||
| e9cd437668 | |||
| aa153f2ee7 | |||
| b1e6b00545 | |||
|
|
4f0ddc85d3 | ||
|
|
5d45702d5f | ||
|
|
d731a5cb09 | ||
|
|
06dfd91a82 | ||
|
|
c540466147 | ||
|
|
4d8b04cda9 | ||
|
|
aed2344bd4 | ||
|
|
c2508f8fa2 | ||
|
|
52d67b0f44 | ||
|
|
8079a476b6 | ||
|
|
2ef944d5c4 | ||
|
|
fde929b151 | ||
|
|
96f1cc1a5c | ||
|
|
647bf8c953 | ||
|
|
d2c7d70f49 | ||
|
|
001629b6dd | ||
|
|
b04469a252 | ||
|
|
54484e56e7 | ||
|
|
adc689cb15 | ||
|
|
d0f96a7023 | ||
|
|
08145f635f | ||
|
|
4884a97223 | ||
|
|
55136c1c6f | ||
|
|
fc300607e5 | ||
|
|
8c20ed0c89 | ||
|
|
c8e9cbdbb8 | ||
|
|
3f70ac5cde | ||
|
|
11a7182594 | ||
|
|
817074a787 | ||
|
|
c75bf1a19d | ||
|
|
11ebb98919 | ||
|
|
e4093343c2 | ||
|
|
101ea554ef | ||
|
|
ef6a986dc6 | ||
|
|
db593496a7 | ||
|
|
00c492891e | ||
|
|
0e81f9c726 | ||
|
|
b419c5cf7c | ||
|
|
20e5a6d1f3 | ||
|
|
99a9a5d850 | ||
|
|
a15d51c3d8 | ||
|
|
b01974b665 | ||
|
|
be5bec9887 | ||
|
|
27045f03f5 | ||
|
|
071baf04fd | ||
|
|
341e34b766 | ||
|
|
5c21816b22 | ||
|
|
afd18db381 | ||
|
|
6c8cd4c9f8 | ||
|
|
255d395f1d | ||
|
|
2f845e98e8 | ||
|
|
1371e3efb8 | ||
|
|
8a2c1658a8 | ||
|
|
b65c200922 | ||
|
|
33caf31237 | ||
|
|
cb7effca05 | ||
|
|
8745a3e824 | ||
|
|
ac6510d481 | ||
|
|
2109c7b830 | ||
|
|
629857d3ef | ||
|
|
60eed202dd | ||
|
|
14e2621a05 | ||
|
|
99da7963d1 | ||
|
|
2abe910ff5 | ||
|
|
15f7941daf | ||
|
|
535b87bb64 | ||
|
|
e63c0d1b03 | ||
|
|
8bc714a2b1 | ||
|
|
07b0aa8f52 | ||
|
|
ce665baa88 | ||
|
|
8c41663175 | ||
|
|
7cb10b71bb | ||
|
|
47cacf5f1a | ||
|
|
042e4b070c | ||
|
|
f84dbb369f | ||
|
|
34ec165bff | ||
|
|
b20c0bdec7 | ||
|
|
c527ad0803 | ||
|
|
0a6bb5190f | ||
|
|
cf353f8829 | ||
|
|
2bd7c021fd | ||
|
|
46f788d1eb | ||
|
|
5ea5d30075 | ||
|
|
22d650469b | ||
|
|
849ad494d8 | ||
|
|
7a2bb38331 | ||
|
|
1428ac2cb0 | ||
|
|
efdc7d9ba0 | ||
|
|
e4e41bb595 | ||
|
|
379fbb6e5d | ||
|
|
09c3236afc | ||
|
|
7d52440461 | ||
|
|
e206995268 | ||
|
|
ab4120721f | ||
|
|
a9c365a5eb | ||
|
|
8ad928d48d | ||
|
|
ebf5efe9f2 | ||
|
|
c7055341f9 | ||
|
|
34c5be5c42 | ||
|
|
1675916fda | ||
|
|
a38c608420 | ||
|
|
20be1d179a | ||
|
|
1870f38099 | ||
|
|
96eced9845 | ||
|
|
92e8c40c55 | ||
|
|
0bfa747382 | ||
|
|
be3c4263b3 | ||
|
|
f00852a619 | ||
|
|
83df8848c8 | ||
|
|
99183ce4e2 | ||
|
|
434ce56e33 | ||
|
|
ec86de2bc4 | ||
|
|
341f3d0ea5 | ||
|
|
579120df70 | ||
|
|
63eb323e8b | ||
|
|
2861ae2823 | ||
|
|
0b947ce2c7 | ||
|
|
2222d6d173 | ||
|
|
33e9b57b78 | ||
|
|
62f4dfdc7a | ||
|
|
7e01fd9c38 | ||
|
|
eefaf7a2b4 | ||
|
|
31dcf99e61 | ||
|
|
0def5f1dca | ||
|
|
ac94374f48 | ||
|
|
9f72b6e2c0 | ||
|
|
f9e38c1a8d | ||
|
|
6db56cc949 | ||
|
|
7081720ecb | ||
|
|
f7ded4d87b | ||
|
|
67780ca4a9 | ||
|
|
871f3c4bfe | ||
|
|
395fe8cb10 | ||
|
|
af936f6f8e | ||
|
|
5512e95e0a | ||
|
|
5e14f18c83 | ||
|
|
5adb971d9a | ||
|
|
f51e5ba19d | ||
|
|
488bddb02a | ||
|
|
3a2ec3ef9c | ||
|
|
08283f6c54 | ||
|
|
f7d3f58318 | ||
|
|
89e84e9b1b | ||
|
|
9226cce151 | ||
|
|
6526bdc824 | ||
|
|
1967f46a69 | ||
|
|
e504d13120 | ||
|
|
2f284f4274 | ||
|
|
4d171b27a4 | ||
|
|
fe4a9a6189 | ||
|
|
c862589dcf | ||
|
|
61765b0e33 | ||
|
|
78a111b57d | ||
|
|
9a515b9234 | ||
|
|
b924c180ae | ||
|
|
737f3eb553 | ||
|
|
6e3954f3bb | ||
|
|
4544f29832 | ||
|
|
477c357f11 | ||
|
|
7869a7c1b0 | ||
|
|
edc7159ef6 | ||
|
|
1db6943702 | ||
|
|
e8dff6c4a0 | ||
|
|
23ed816035 | ||
|
|
324b7f38a9 | ||
|
|
aa7aff3f6b | ||
|
|
236929a166 | ||
|
|
953e243639 | ||
|
|
338d53c982 | ||
|
|
37ebcc509b | ||
|
|
f9be6f9a85 | ||
|
|
2cc2b5b856 | ||
|
|
194976135f | ||
|
|
ef17f3ea7d | ||
|
|
0eec6fcfb6 | ||
|
|
09a772419a | ||
|
|
6c035d01d4 | ||
|
|
97bddc4537 | ||
|
|
684675bd84 | ||
|
|
b8c0fa9fa0 | ||
|
|
9e7794cd66 | ||
|
|
92ad44abf9 | ||
|
|
7e83ddf80e | ||
|
|
a9be720f09 | ||
|
|
d7906f113e | ||
|
|
01dcaefcfb | ||
|
|
cfba91ea43 | ||
|
|
134b6f6478 | ||
|
|
64104cb182 | ||
|
|
9aedcc7997 | ||
|
|
35547e28ea | ||
|
|
c6543e1f95 | ||
|
|
2183875e9e | ||
|
|
e5ee069f4a | ||
|
|
6c844315aa | ||
|
|
872bb1388d | ||
|
|
42aa255152 | ||
|
|
e58188d136 | ||
|
|
bb32c0af3b | ||
|
|
63fd2c7037 | ||
|
|
520a2ba202 | ||
|
|
13e8445083 | ||
|
|
d1c70cb13b | ||
|
|
6898cff623 | ||
|
|
f4558e3c41 | ||
|
|
d24075b1c5 | ||
|
|
a8c2a9da3a | ||
|
|
8041df7d41 | ||
|
|
073a181778 | ||
|
|
bec6fdc66a | ||
|
|
6833c9f1c2 | ||
|
|
18ade30185 | ||
|
|
e7ab305335 | ||
|
|
110d3a453a | ||
|
|
f5aeab39b4 | ||
|
|
e7738895ce | ||
|
|
60446dfc20 | ||
|
|
dc211c9c44 | ||
|
|
27babac6dc | ||
|
|
3e2b7cddc8 | ||
|
|
80ba2b3ccc | ||
|
|
b730582336 | ||
|
|
1b429dd2e5 | ||
|
|
448404e45c | ||
|
|
562d84c375 | ||
|
|
f09e3362aa | ||
|
|
51b5b1c08c | ||
|
|
ca2dde9a41 | ||
|
|
6674d1ed0f | ||
|
|
2a10dffff8 | ||
|
|
e0b17fc97d | ||
|
|
52800c3a65 | ||
|
|
9124617055 | ||
|
|
b312712d1b | ||
|
|
5bc1b8695e | ||
|
|
d921f3dadb | ||
|
|
c154712012 | ||
|
|
3634af3fdc | ||
|
|
1df9ec9f0f | ||
|
|
ae54a94d41 | ||
|
|
69add504e6 | ||
|
|
a0d30b6872 | ||
|
|
a06b33be66 | ||
|
|
fe3e33e702 | ||
|
|
3f56459734 | ||
|
|
4903241e4b | ||
|
|
85be003cf5 | ||
|
|
bddc1c0f9d | ||
|
|
01f6d83b86 | ||
|
|
aa994ee4fb | ||
|
|
d058a70557 | ||
|
|
7298468df7 | ||
|
|
63caa5044d | ||
|
|
2ae93dbec6 | ||
|
|
b434bead2c | ||
|
|
6284b155b8 | ||
|
|
b12c2d17d5 | ||
|
|
5fb1e26a4c | ||
|
|
6423750250 | ||
|
|
d9b5ef1cee | ||
|
|
f1717bde51 | ||
|
|
c6f4f40bba | ||
|
|
65f1b1e1e3 | ||
|
|
ad91ef66bd | ||
|
|
6bfa593988 | ||
|
|
3ea580b537 | ||
|
|
87b0b493eb | ||
|
|
4eb4a2de00 | ||
|
|
1f2f57b03b | ||
|
|
4afaad3df5 | ||
|
|
c3ba2e0f94 | ||
|
|
693c3168da | ||
|
|
8f309bc768 | ||
|
|
1a0d6a90c2 | ||
|
|
7f2019b4af | ||
|
|
ee7f0a2016 | ||
|
|
644b417f6c | ||
|
|
471576d6e8 | ||
|
|
7ee8aa7838 | ||
|
|
af63e9a7ad | ||
|
|
95c7344557 | ||
|
|
0c936e54ba | ||
|
|
62b90c29db | ||
|
|
6911b499d3 | ||
|
|
44f4c9374d | ||
|
|
11dabbe44d | ||
|
|
0a5a3845db | ||
|
|
5b797328f2 | ||
|
|
b89f1ad7d8 | ||
|
|
b0104d9992 | ||
|
|
9d8f4c774f | ||
|
|
8b7a22ecd9 | ||
|
|
a4e6db8d76 | ||
|
|
78506d5249 | ||
|
|
6747b18b75 | ||
|
|
544f13c52a | ||
|
|
4644f6e96b | ||
|
|
a3b228399b | ||
|
|
100a557c7c | ||
|
|
6acc75ccff | ||
|
|
b41f9620fa | ||
|
|
58bde08425 | ||
|
|
7d6c6edab3 | ||
|
|
d209964718 | ||
|
|
c03f659efb | ||
|
|
2e66cbeb60 | ||
|
|
19409cb999 | ||
|
|
c06182c38f | ||
|
|
f79cd8cee3 | ||
|
|
c130739de0 | ||
|
|
1a4a1583d5 | ||
|
|
3633ca04eb | ||
|
|
e61c0c45aa | ||
|
|
6d81848f25 | ||
|
|
10b3b343dd | ||
|
|
f6fd025be2 | ||
|
|
b5897687a6 | ||
|
|
ebeae261de | ||
|
|
9733f3c02c | ||
|
|
217c8a3933 | ||
|
|
7188d81ad4 | ||
|
|
48cacd6d9d | ||
|
|
1e378a514d | ||
|
|
92ab5e18ee | ||
|
|
b42af10905 | ||
|
|
afe8158cb7 | ||
|
|
a05bea0af5 | ||
|
|
e1514a151c | ||
|
|
2a82cfdb2a | ||
|
|
49da433879 | ||
|
|
92388e1734 | ||
|
|
3860c25dc0 | ||
|
|
25ee5ed1f9 | ||
|
|
566214ac62 | ||
|
|
1459f10803 | ||
|
|
0795a39459 | ||
|
|
e5831d6807 | ||
|
|
88bdb5114f | ||
|
|
90bd9088bb | ||
|
|
01cf8ab82c | ||
|
|
aee5506f00 | ||
|
|
b6183f2de1 | ||
|
|
452e0fe553 | ||
|
|
2f341a3369 | ||
|
|
66e55d1a1f | ||
|
|
63fac32bc0 | ||
|
|
aaeaeba57c | ||
|
|
d3c56897a3 | ||
|
|
0c2c3ec862 | ||
|
|
b6e7b18c7b | ||
|
|
55d049b1e8 | ||
|
|
8c0601816f | ||
|
|
350cde08d8 | ||
|
|
db5a29fd9a | ||
|
|
0716605e94 | ||
|
|
c802480d75 | ||
|
|
2519431f02 | ||
|
|
b38e71e544 | ||
|
|
c981afcf31 | ||
|
|
eccb8a4faf | ||
|
|
7fa5ddfc44 | ||
|
|
054f4e77f5 | ||
|
|
1398d6cc21 | ||
|
|
b902b019fb | ||
|
|
5e589aba3c | ||
|
|
c28cee88b7 | ||
|
|
14a45dc546 | ||
|
|
883621ba34 | ||
|
|
067cc81ebb | ||
|
|
b19ee7b894 | ||
|
|
1b356d3bf2 | ||
|
|
94a4059b4a | ||
|
|
735a0023cc | ||
|
|
2ad4fa99ed | ||
|
|
c0950c5fc6 | ||
|
|
afbbbbd4f2 | ||
|
|
32812c9482 | ||
|
|
c70e806d74 | ||
|
|
05be2e7386 | ||
|
|
e2e8885ce3 | ||
|
|
b214d8b6ee | ||
|
|
ba98bb9334 | ||
|
|
630a578e1d | ||
|
|
0bb35d7e7f | ||
|
|
357296baeb | ||
|
|
bff525d26f | ||
|
|
e4bdb21a54 | ||
|
|
c0ac7f0ac8 | ||
|
|
eba2fe1624 | ||
|
|
0030fe3aeb | ||
|
|
aaabf82eff | ||
|
|
de91d28f6f | ||
|
|
24d5d200b8 | ||
|
|
573ba2ee43 | ||
|
|
b4fced4bd7 | ||
|
|
52310a8ad8 | ||
|
|
11d203c54a | ||
|
|
723f12923c | ||
|
|
8b106dbc6c | ||
|
|
955d5a136f | ||
|
|
2db3825940 | ||
|
|
db3253e5d2 | ||
|
|
dbde8383c9 | ||
|
|
6d552f15b6 | ||
|
|
ba15724a62 | ||
|
|
938d286fb6 | ||
|
|
2e6c7b1bb8 | ||
|
|
5be705ca2a | ||
|
|
07b4cfaeae | ||
|
|
c9379b3608 | ||
|
|
22c8c96249 | ||
|
|
d66828c2bf | ||
|
|
a244f3ba4d | ||
|
|
0c20d35206 | ||
|
|
462ea26303 | ||
|
|
b25632ebc4 | ||
|
|
2a2b3f72fb | ||
|
|
52819d39d9 | ||
|
|
1d41ff16d6 | ||
|
|
36dd245ee3 | ||
|
|
e0bc35b975 | ||
|
|
893bafa14b | ||
|
|
7d262ad50b | ||
|
|
d9e7862cea | ||
|
|
9f30c299ee | ||
|
|
39845444cc | ||
|
|
ec32db2dd6 | ||
|
|
411e8ed79d | ||
|
|
c1c2a9f1a1 | ||
|
|
2850e56f30 | ||
|
|
9c0354bbf1 | ||
|
|
c09f1c2443 | ||
|
|
912f2c3567 | ||
|
|
ad51998d67 | ||
|
|
1049080df5 | ||
|
|
966b00617e | ||
|
|
b408208e4c | ||
|
|
a1edc2c6a9 | ||
|
|
2a06261f75 | ||
|
|
0b58465fb9 | ||
|
|
f67a93eddc | ||
|
|
7044f0e2cf | ||
|
|
ed7a88ce66 | ||
|
|
e392160435 | ||
|
|
5c0a3102ff | ||
|
|
2032c7c1f7 | ||
|
|
d295d8b43c | ||
|
|
ee8bac9ad7 | ||
|
|
4863bd30d7 | ||
|
|
7070a14480 | ||
|
|
a38f25f7cd | ||
|
|
a5259073df | ||
|
|
3e5ce46e98 | ||
|
|
f746866b65 | ||
|
|
8f31a1a820 | ||
|
|
4187568522 | ||
|
|
da82048d77 | ||
|
|
04d1caff78 | ||
|
|
bea06da531 | ||
|
|
7643f3cf7b | ||
|
|
aa5c6bbf08 | ||
|
|
9536f2a909 | ||
|
|
c7475d78b4 | ||
|
|
3c9a07677e | ||
|
|
b669f57068 | ||
|
|
ccebe536b3 | ||
|
|
b9a0733062 | ||
|
|
5961b45140 | ||
|
|
5f53738376 | ||
|
|
5eb4a7d711 | ||
|
|
f717081893 | ||
|
|
01b5118c6f |
43
.env
Normal file
43
.env
Normal file
@@ -0,0 +1,43 @@
|
||||
# In all environments, the following files are loaded if they exist,
|
||||
# the latter taking precedence over the former:
|
||||
#
|
||||
# * .env contains default values for the environment variables needed by the app
|
||||
# * .env.local uncommitted file with local overrides
|
||||
# * .env.$APP_ENV committed environment-specific defaults
|
||||
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
||||
#
|
||||
# Real environment variables win over .env files.
|
||||
#
|
||||
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||
#
|
||||
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
APP_SECRET=6a9ac3a09c73230107373e8e0b71e0a3
|
||||
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||
#TRUSTED_HOSTS='^(localhost|example\.com)$'
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/mailer ###
|
||||
# MAILER_DSN=smtp://localhost
|
||||
###< symfony/mailer ###
|
||||
|
||||
###> doctrine/doctrine-bundle ###
|
||||
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
|
||||
# For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8"
|
||||
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||
DATABASE_URL=postgresql://postgres:foobar@postgres:5432/social
|
||||
#?serverVersion=11&charset=utf8
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
SHELL_VERBOSITY=3
|
||||
###> symfony/messenger ###
|
||||
# Choose one of the transports below
|
||||
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
|
||||
MESSENGER_TRANSPORT_DSN_HIGH=doctrine://default?queue_name=high
|
||||
MESSENGER_TRANSPORT_DSN_LOW=doctrine://default?queue_name=low
|
||||
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
|
||||
###< symfony/messenger ###
|
||||
6
.env.test
Normal file
6
.env.test
Normal file
@@ -0,0 +1,6 @@
|
||||
# define your env variables for the test env here
|
||||
KERNEL_CLASS='App\Kernel'
|
||||
APP_SECRET='$ecretf0rt3st'
|
||||
SYMFONY_DEPRECATIONS_HELPER=999999
|
||||
PANTHER_APP_ENV=panther
|
||||
DATABASE_URL=postgresql://postgres:password@db:5432/social
|
||||
79
.gitignore
vendored
79
.gitignore
vendored
@@ -1,18 +1,63 @@
|
||||
avatar/
|
||||
files/
|
||||
file/
|
||||
local/
|
||||
logs/
|
||||
log/
|
||||
run/
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
/.env.local
|
||||
/.env.local.php
|
||||
/.env.*.local
|
||||
/config/secrets/prod/prod.decrypt.private.php
|
||||
/public/bundles/
|
||||
/var/
|
||||
/vendor/
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/phpunit-bridge ###
|
||||
.phpunit
|
||||
.phpunit.result.cache
|
||||
/phpunit.xml
|
||||
###< symfony/phpunit-bridge ###
|
||||
|
||||
###> friendsofphp/php-cs-fixer ###
|
||||
!.php_cs
|
||||
/.php_cs.cache
|
||||
###< friendsofphp/php-cs-fixer ###
|
||||
|
||||
###> phpunit/phpunit ###
|
||||
/phpunit.xml
|
||||
.phpunit.result.cache
|
||||
###< phpunit/phpunit ###
|
||||
|
||||
|
||||
DOCUMENTATION/database/*
|
||||
!DOCUMENTATION/database/database.pdf
|
||||
|
||||
docker/certbot/.files
|
||||
docker/certbot/www
|
||||
docker/*/*.env
|
||||
|
||||
docker/mail/etc/hostname
|
||||
docker/mail/etc/hosts
|
||||
docker/mail/etc/resolv.conf
|
||||
docker/mail/config/aliases.db
|
||||
docker/mail/config/domains.db
|
||||
docker/mail/config/mailboxes.db
|
||||
docker/mail/config/passwd.db
|
||||
docker/mail/etc/service/*
|
||||
!docker/mail/etc/service/*/run
|
||||
|
||||
!docker/testing/*
|
||||
!docker/testing/docker-compose.yaml
|
||||
docker/testing/*~
|
||||
|
||||
docker-compose.yaml
|
||||
composer.local.json
|
||||
|
||||
social.local.yaml
|
||||
|
||||
# V2
|
||||
config.php
|
||||
.htaccess
|
||||
httpd.conf
|
||||
dataobject.ini
|
||||
*.bak
|
||||
*.orig
|
||||
*.rej
|
||||
TODO.rym
|
||||
config-*.php
|
||||
good-config.php
|
||||
*.mo
|
||||
/file
|
||||
|
||||
notes
|
||||
|
||||
|
||||
.test_coverage_report
|
||||
.phpunit_cache
|
||||
278
.php_cs
Normal file
278
.php_cs
Normal file
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This document has been generated with
|
||||
* https://mlocati.github.io/php-cs-fixer-configurator/#version:2.16.1|configurator
|
||||
* you can change this configuration by importing this file.
|
||||
*/
|
||||
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'],
|
||||
// PHP arrays should be declared using the configured syntax.
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
// Binary operators should be surrounded by space as configured.
|
||||
'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' => 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_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,
|
||||
// Remove extra spaces in a nullable typehint.
|
||||
'compact_nullable_typehint' => true,
|
||||
// Concatenation should be spaced according configuration.
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
// The PHP constants `true`, `false`, and `null` MUST be written using the correct casing.
|
||||
'constant_case' => true,
|
||||
// Equal sign in declare statement should be surrounded by spaces or not following configuration.
|
||||
'declare_equal_normalize' => ['space' => 'single'],
|
||||
// Replaces `dirname(__FILE__)` expression with equivalent `__DIR__` constant.
|
||||
'dir_constant' => true,
|
||||
// PHP code MUST use only UTF-8 without BOM (remove BOM).
|
||||
'encoding' => true,
|
||||
// Replace deprecated `ereg` regular expression functions with `preg`.
|
||||
'ereg_to_preg' => true,
|
||||
// Escape implicit backslashes in strings and heredocs to ease the understanding of which are special chars interpreted by PHP and which not.
|
||||
'escape_implicit_backslashes' => true,
|
||||
// Add curly braces to indirect variables to make them clear to understand. Requires PHP >= 7.0.
|
||||
'explicit_indirect_variable' => true,
|
||||
// Converts implicit variables into explicit ones in double-quoted strings or heredoc syntax.
|
||||
'explicit_string_variable' => true,
|
||||
// PHP code must use the long `<?php` tags or short-echo `<?=` tags and not other tag variations.
|
||||
'full_opening_tag' => true,
|
||||
// Transforms imported FQCN parameters and return types in function arguments to short version.
|
||||
'fully_qualified_strict_types' => true,
|
||||
// Spaces should be properly placed in a function declaration.
|
||||
'function_declaration' => ['closure_function_spacing' => 'one'],
|
||||
// Ensure single space between function's argument and its typehint.
|
||||
'function_typehint_space' => 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,
|
||||
// All PHP files must use same line ending.
|
||||
'line_ending' => true,
|
||||
// Use `&&` and `||` logical operators instead of `and` and `or`.
|
||||
'logical_operators' => true,
|
||||
// PHP keywords MUST be in lower case.
|
||||
'lowercase_keywords' => true,
|
||||
// Class static references `self`, `static` and `parent` MUST be in lower case.
|
||||
'lowercase_static_reference' => true,
|
||||
// Magic constants should be referred to using the correct casing.
|
||||
'magic_constant_casing' => true,
|
||||
// Magic method definitions and calls must be using the correct casing.
|
||||
'magic_method_casing' => 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.
|
||||
'multiline_comment_opening_closing' => true,
|
||||
// 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' => 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' => false,
|
||||
// Native type hints for functions should use the correct case.
|
||||
'native_function_type_declaration_casing' => 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.
|
||||
'no_blank_lines_after_phpdoc' => true,
|
||||
// There must be a comment when fall-through is intentional in a non-empty case body.
|
||||
'no_break_comment' => true,
|
||||
// The closing `? >` tag MUST be omitted from files containing only PHP.
|
||||
'no_closing_tag' => true,
|
||||
// There should not be any empty comments.
|
||||
'no_empty_comment' => true,
|
||||
// There should not be empty PHPDoc blocks.
|
||||
'no_empty_phpdoc' => true,
|
||||
// Remove useless semicolon statements.
|
||||
'no_empty_statement' => true,
|
||||
// Removes extra blank lines and/or blank lines following configuration.
|
||||
'no_extra_blank_lines' => true,
|
||||
// Remove leading slashes in `use` clauses.
|
||||
'no_leading_import_slash' => true,
|
||||
// The namespace declaration line shouldn't contain leading whitespace.
|
||||
'no_leading_namespace_whitespace' => true,
|
||||
// Either language construct `print` or `echo` should be used.
|
||||
'no_mixed_echo_print' => true,
|
||||
// Operator `=>` should not be surrounded by multi-line whitespaces.
|
||||
'no_multiline_whitespace_around_double_arrow' => true,
|
||||
// Properties MUST not be explicitly initialized with `null` except when they have a type declaration (PHP 7.4).
|
||||
'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,
|
||||
// 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,
|
||||
// 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.
|
||||
'no_trailing_comma_in_singleline_array' => true,
|
||||
// Remove trailing whitespace at the end of non-blank lines.
|
||||
'no_trailing_whitespace' => true,
|
||||
// There MUST be no trailing spaces inside comment or PHPDoc.
|
||||
'no_trailing_whitespace_in_comment' => true,
|
||||
// Removes unneeded parentheses around control statements.
|
||||
'no_unneeded_control_parentheses' => true,
|
||||
// Removes unneeded curly braces that are superfluous and aren't part of a control structure's body.
|
||||
'no_unneeded_curly_braces' => true,
|
||||
// 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' => 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.
|
||||
'no_whitespace_before_comma_in_array' => true,
|
||||
// Remove trailing whitespace at the end of blank lines.
|
||||
'no_whitespace_in_blank_line' => true,
|
||||
// Remove Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols.
|
||||
'non_printable_character' => true,
|
||||
// Array index should always be written by using square braces.
|
||||
'normalize_index_brace' => true,
|
||||
// There should not be space before or after object `T_OBJECT_OPERATOR` `->`.
|
||||
'object_operator_without_whitespace' => 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 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,
|
||||
// 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`.
|
||||
'php_unit_strict' => true,
|
||||
// Calls to `PHPUnit\Framework\TestCase` static methods must all be of the same type, either `$this->`, `self::` or `static::`.
|
||||
'php_unit_test_case_static_method_calls' => true,
|
||||
// PHPDoc should contain `@param` for all params.
|
||||
'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,
|
||||
// Docblocks should have the same indentation as the documented subject.
|
||||
'phpdoc_indent' => 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,
|
||||
// Annotations in PHPDoc should be ordered so that `@param` annotations come first, then `@throws` annotations, then `@return` annotations.
|
||||
'phpdoc_order' => true,
|
||||
// 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`.
|
||||
'phpdoc_scalar' => true,
|
||||
// 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' => 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.
|
||||
'phpdoc_types' => true,
|
||||
// Sorts PHPDoc types.
|
||||
'phpdoc_types_order' => true,
|
||||
// `@var` and `@type` annotations must have type and name in the correct order.
|
||||
'phpdoc_var_annotation_correct_order' => 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.
|
||||
'self_accessor' => true,
|
||||
// Instructions must be terminated with a semicolon.
|
||||
'semicolon_after_instruction' => true,
|
||||
// Cast shall be used, not `settype`.
|
||||
'set_type_to_cast' => true,
|
||||
// Cast `(boolean)` and `(integer)` should be written as `(bool)` and `(int)`, `(double)` and `(real)` as `(float)`, `(binary)` as `(string)`.
|
||||
'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,
|
||||
// There should be exactly one blank line before a namespace declaration.
|
||||
'single_blank_line_before_namespace' => 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,
|
||||
// Each trait `use` must be done as single statement.
|
||||
'single_trait_insert_per_statement' => true,
|
||||
// Fix whitespace after a semicolon.
|
||||
'space_after_semicolon' => true,
|
||||
// Increment and decrement operators should be used if possible.
|
||||
'standardize_increment' => true,
|
||||
// Replace all `<>` with `!=`.
|
||||
'standardize_not_equals' => 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,
|
||||
// Standardize spaces around ternary operator.
|
||||
'ternary_operator_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,
|
||||
// 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__)
|
||||
);
|
||||
@@ -1,95 +0,0 @@
|
||||
## Code of Conduct
|
||||
|
||||
### Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
### Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
### Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
### Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
### Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at mattl@gnu.org. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
### Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
|
||||
|
||||
## The Code of Conflict
|
||||
|
||||
GNU social has a high submission standard and we want to keep quality code in the
|
||||
codebase and bad code out of it. As such your code will be closely scrutinized,
|
||||
and you might take this criticism personally. Please understand that this is
|
||||
meant to keep the standards of the codebase up, and isn't meant personally. All
|
||||
the same, this isn't an excuse for poor behaviour, and a reviewer shouldn't be
|
||||
misbehaving towards submitters.
|
||||
|
||||
|
||||
If however, anyone feels personally abused, threatened, or otherwise
|
||||
uncomfortable due to this process, that is not acceptable. If so, please
|
||||
contact the project team at mattl@gnu.org, and they will work to resolve the issue
|
||||
to the best of their ability.
|
||||
|
||||
As a reviewer of code, please strive to keep things civil and focused on the
|
||||
technical issues involved. We are all humans, and frustrations can be high on
|
||||
both sides of the process. Try to keep in mind the immortal words of Bill and
|
||||
Ted, "Be excellent to each other."
|
||||
112
CONTRIBUTING.md
112
CONTRIBUTING.md
@@ -1,112 +0,0 @@
|
||||
# Contributing to GNU social
|
||||
|
||||
First of all, if you're reading this intending to contribute to GNU social,
|
||||
thanks! Free software development only happens when people like you take an
|
||||
interest in giving back to the software they themselves use, and their
|
||||
community.
|
||||
|
||||
When contributing to this repository, please first discuss the change you wish to
|
||||
make via issue, email, or any other method with the owners of this repository before
|
||||
making a change.
|
||||
|
||||
There's a few files you should read before going forward with a merge request
|
||||
or a patch submission. They detail what this file touches on in brief. They
|
||||
are:
|
||||
|
||||
* `DOCUMENTATION/DEVELOPERS/CONTRIBUTING/coding_standards.md`: How your code should be structured and formatted to be
|
||||
accepted into the GNU social codebase.
|
||||
* `/DOCUMENTATION/DEVELOPERS/CONTRIBUTING/merge_request_checklist.md`: A quick checklist to review before submission.
|
||||
|
||||
|
||||
## Merge Request Process
|
||||
|
||||
1. Ensure you strip any trailing spaces off and checked the file with php-cs-fixer
|
||||
2. Increase the version numbers in any examples files and the README.md to the new version that this
|
||||
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
|
||||
3. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
|
||||
do not have permission to do that, you may request the second reviewer to merge it for you.
|
||||
|
||||
|
||||
## Coding Standards
|
||||
|
||||
Since we will be expected to maintain your code once it's submitted, we ask you
|
||||
to adhere to certain coding standards that make it easier for us to do so. If
|
||||
code doesn't follow them, it will be rejected, so please read up on these.
|
||||
|
||||
|
||||
## Bug Reports
|
||||
|
||||
Please report bugs to the issue tracker at
|
||||
<https://notabug.org/diogo/gnu-social/issues> Avoid assigning the labels
|
||||
yourself, as these are for the development team to assign priority and area of
|
||||
coverage to a subject. Please only submit something here if you are certain it
|
||||
is a bug or represents a feature enhancement that we do not presently have. If
|
||||
you are uncertain whether it's a bug, please feel free to ask
|
||||
at #social IRC channel on freenode.net https://www.freenode.net/.
|
||||
|
||||
When reporting a bug, please try to include as much information as possible,
|
||||
including the environment being run on (if it's a common LAMP stack just give
|
||||
us version numbers of the main stack components, that's fine), and the specific
|
||||
error you get. If you do not get a client-facing error, please check the PHP
|
||||
error_log and ensure there isn't something silently reported there, as well as
|
||||
the GNU social log. Try to include steps to reproduce the error as well, as if
|
||||
we cannot reproduce the error, we can't fix it!
|
||||
|
||||
It is perfectly acceptable to reference the archive page of a discussion on the
|
||||
mailing list for the bug report, by the way, as long as it includes all the
|
||||
information we need for a bug report.
|
||||
|
||||
|
||||
## Submitting Feature Requests / Enhancement Requests
|
||||
|
||||
Social media is constantly evolving, and we welcome ideas about how we can
|
||||
change and evolve GNU social to keep it the excellent piece of software that it
|
||||
is. However, there are a few things we ask you do when submitting feature
|
||||
requests:
|
||||
|
||||
1. Understand that since we have a limited amount of developers and these people
|
||||
contribute in their free time, we may prioritize things differently than you
|
||||
value them. Oftentimes this is because certain requests involve less changes
|
||||
to the existing codebase than others, and therefore this makes them easier
|
||||
to add.
|
||||
2. Please search the existing feature requests and enhancements to see if a
|
||||
similar request exists. If one does but you have different ideas about how
|
||||
to do it or what it should entail, please add a comment to the existing idea
|
||||
rather than create a new one for your "version" of it. Duplicate submissions
|
||||
mean we spend more time maintaining the tracker and less time actually
|
||||
working on the codebase!
|
||||
3. When outlining the way that you see something working, don't be afraid to be
|
||||
as detailed as possible! We may not implement it exactly as you describe for
|
||||
any variety of reasons, but the more concrete and fleshed out an idea is, the
|
||||
easier it is for us to know what you want and be able to implement it in a
|
||||
sane and secure fashion.
|
||||
4. When describing a possible new idea and its mechanisms of operation, the key
|
||||
words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the issue submission
|
||||
are to be interpreted as described in RFC 2119.
|
||||
<https://tools.ietf.org/html/rfc2119>
|
||||
|
||||
Finally, and just as a call back to the first point, realize just because we
|
||||
might not rush to implement something, doesn't mean that we don't want to
|
||||
implement it! We would rather take the time to do something right the first
|
||||
time, then hurriedly apply a new idea, or a fix, only to have to patch it later.
|
||||
|
||||
|
||||
## Branch of Code Submissions
|
||||
|
||||
Unless you've been specifically directed otherwise, all submissions of code
|
||||
should be against the `nightly` branch, so make sure any modifications are based
|
||||
on Nightly.
|
||||
|
||||
|
||||
## Copyright / Licensing
|
||||
|
||||
You acknowledge that by submitting code to GNU social, you are licensing it under
|
||||
the GNU AGPLv3 unless there is an extenuating circumstance where it would be
|
||||
licensed differently (such as modifications to an external library we include
|
||||
such as Stomp).
|
||||
|
||||
You also acknowledge that unless you assign a copyright explicitly, it will be
|
||||
assumed to be assigned to GNU social.
|
||||
|
||||
Thanks for considering submission, and happy hacking!
|
||||
661
COPYING
661
COPYING
@@ -1,661 +0,0 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
116
CREDITS.md
116
CREDITS.md
@@ -8,55 +8,55 @@ anyone's been overlooked in error.
|
||||
|
||||
Current team
|
||||
------------
|
||||
* Matt Lee
|
||||
* Mikael Nordfeldth
|
||||
* Diogo Cordeiro
|
||||
* Bruno Casteleiro
|
||||
* Miguel Dantas
|
||||
* Alexei Sorokin
|
||||
* Bruno Casteleiro
|
||||
* Diogo Cordeiro
|
||||
* Hugo Sales
|
||||
|
||||
Additional Contributors
|
||||
-----------------------
|
||||
* Ciaran Gultnieks
|
||||
* Michael Landers
|
||||
* Ori Avtalion
|
||||
* Garret Buell
|
||||
* Mike Cochrane
|
||||
* Matthew Gregg
|
||||
* Sean Murphy
|
||||
* Leslie Michael Orchard
|
||||
* Eric Helgeson
|
||||
* Ken Sedgwick
|
||||
* Brian Hendrickson
|
||||
* Tobias Diekershoff
|
||||
* Dan Moore
|
||||
* Fil
|
||||
* Jeff Mitchell
|
||||
* Brenda Wallace
|
||||
* Jeffery To
|
||||
* Federico Marani
|
||||
* mEDI
|
||||
* Brett Taylor
|
||||
* Brigitte Schuster
|
||||
* Craig Andrews
|
||||
* Donald Robertson
|
||||
* Deb Nicholson
|
||||
* Ian Denhart
|
||||
* Steven DuBois
|
||||
* Blaine Cook
|
||||
* Henry Story
|
||||
* Melvin Carvalho
|
||||
* chimo
|
||||
* Akio
|
||||
* Maiyannah Bishop
|
||||
* Blaine Cook
|
||||
* Bob Mottram
|
||||
* David Yip
|
||||
* Neil E Hodges
|
||||
* Moonman
|
||||
* Normandy
|
||||
* Verius
|
||||
* Alexei Sorokin
|
||||
* Brenda Wallace
|
||||
* Brett Taylor
|
||||
* Brian Hendrickson
|
||||
* Brigitte Schuster
|
||||
* Ciaran Gultnieks
|
||||
* Craig Andrews
|
||||
* Daniel Supernault
|
||||
* Dan Moore
|
||||
* David Yip
|
||||
* Deb Nicholson
|
||||
* Donald Robertson
|
||||
* Eric Helgeson
|
||||
* Federico Marani
|
||||
* Fil
|
||||
* Garret Buell
|
||||
* Henry Story
|
||||
* Ian Denhart
|
||||
* Jeffery To
|
||||
* Jeff Mitchell
|
||||
* Ken Sedgwick
|
||||
* Leslie Michael Orchard
|
||||
* Maiyannah Bishop
|
||||
* Matthew Gregg
|
||||
* Matt Lee
|
||||
* mEDI
|
||||
* Melvin Carvalho
|
||||
* Michael Landers
|
||||
* Miguel Dantas
|
||||
* Mikael Nordfeldth
|
||||
* Mike Cochrane
|
||||
* Moonman
|
||||
* Neil E Hodges
|
||||
* Normandy
|
||||
* Ori Avtalion
|
||||
* Sean Murphy
|
||||
* Stéphane Bérubé
|
||||
* Steven DuBois
|
||||
* Tobias Diekershoff
|
||||
* Verius
|
||||
|
||||
Credits for StatusNet
|
||||
--------------
|
||||
@@ -65,24 +65,24 @@ Leads
|
||||
* Zach Copley
|
||||
|
||||
Team
|
||||
* Earle Martin
|
||||
* Marie-Claude Doyon
|
||||
* Sarven Capadisli
|
||||
* Robin Millette
|
||||
* Brion Vibber
|
||||
* James Walker
|
||||
* Samantha Doherty
|
||||
* Florian Biree
|
||||
* Erik Stambaugh
|
||||
* 'drry'
|
||||
* Gina Haeussge
|
||||
* Tryggvi Björgvinsson
|
||||
* Adrian Lang
|
||||
* Ori Avtalion
|
||||
* Meitar Moscovitz
|
||||
* Ken Sheppardson
|
||||
* Simon Waters, Surevine
|
||||
* Brion Vibber
|
||||
* 'drry'
|
||||
* Earle Martin
|
||||
* Erik Stambaugh
|
||||
* Florian Biree
|
||||
* Gina Haeussge
|
||||
* James Walker
|
||||
* Joshua Judson Rosen (rozzin)
|
||||
* Ken Sheppardson
|
||||
* Marie-Claude Doyon
|
||||
* Meitar Moscovitz
|
||||
* Ori Avtalion
|
||||
* Robin Millette
|
||||
* Samantha Doherty
|
||||
* Sarven Capadisli
|
||||
* Simon Waters, Surevine
|
||||
* Tryggvi Björgvinsson
|
||||
|
||||
Translators
|
||||
-----------
|
||||
|
||||
@@ -1,61 +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/>.
|
||||
|
||||
/**
|
||||
* Description of this file.
|
||||
*
|
||||
* @package samples
|
||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||
* @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace samples;
|
||||
|
||||
defined('GNUSOCIAL') || die();
|
||||
|
||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'SampleHandler.php');
|
||||
|
||||
/**
|
||||
* Description of this class.
|
||||
*
|
||||
* @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class MySampleClass
|
||||
{
|
||||
/**
|
||||
* Constructor for the sample class.
|
||||
*
|
||||
* @param string $dummy_word just because.
|
||||
* @param int $result another just because.
|
||||
*/
|
||||
public function __construct(string $dummy_word = '', int $result = null)
|
||||
{
|
||||
global $demo;
|
||||
$this->niceWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
* How cool is this function.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function niceWorld() : string
|
||||
{
|
||||
return 'hello, world.';
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
GNU social Coding Style
|
||||
===========================
|
||||
|
||||
Please comply with [PSR-2](https://www.php-fig.org/psr/psr-2/) and the following standard when working on GNU social
|
||||
if you want your patches accepted and modules included in supported releases.
|
||||
|
||||
If you see code which doesn't comply with the below, please fix it :)
|
||||
|
||||
|
||||
Strings
|
||||
-------------------------------------------------------------------------------
|
||||
Use `'` instead of `"` for strings, where substitutions aren't required.
|
||||
This is a performance issue, and prevents a lot of inconsistent coding styles.
|
||||
When using substitutions, use curly braces around your variables - like so:
|
||||
|
||||
$var = "my_var: {$my_var}";
|
||||
|
||||
|
||||
Comments and Documentation
|
||||
-------------------------------------------------------------------------------
|
||||
Comments go on the line ABOVE the code, NOT to the right of the code, unless it is very short.
|
||||
All functions and methods are to be documented using PhpDocumentor - https://docs.phpdoc.org/guides/
|
||||
|
||||
File Headers
|
||||
-------------------------------------------------------------------------------
|
||||
File headers follow a consistent format, as such:
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Description of this file.
|
||||
*
|
||||
* @package samples
|
||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||
* @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
Please use it.
|
||||
|
||||
A few notes:
|
||||
|
||||
* The description of the file doesn't have to be exhaustive. Rather it's
|
||||
meant to be a short summary of what's in this file and what it does. Try
|
||||
to keep it to 1-5 lines. You can get more in-depth when documenting
|
||||
individual functions!
|
||||
|
||||
* You'll probably see files with multiple authors, this is by
|
||||
design - many people contributed to GNU social or its forebears! If you
|
||||
are modifying an existing file, APPEND your own author line, and update
|
||||
the copyright year if needed. Do not replace existing ones.
|
||||
|
||||
You may find `boilerplate.php` useful when creating a new file from scratch.
|
||||
|
||||
Paragraph spacing
|
||||
-------------------------------------------------------------------------------
|
||||
Where-ever possible, try to keep the lines to 80 characters. Don't
|
||||
sacrifice readability for it though - if it makes more sense to have it in
|
||||
one longer line, and it's more easily read that way, that's fine.
|
||||
|
||||
With assignments, avoid breaking them down into multiple lines unless
|
||||
neccesary, except for enumerations and arrays.
|
||||
|
||||
|
||||
'If' statements format
|
||||
-------------------------------------------------------------------------------
|
||||
Use switch statements where many else if's are going to be used. Switch/case is faster
|
||||
|
||||
if ($var == 'example') {
|
||||
echo 'This is only an example';
|
||||
} else {
|
||||
echo 'This is not a test. This is the real thing';
|
||||
}
|
||||
|
||||
Do NOT make if statements like this:
|
||||
|
||||
if ($var == 'example'){ echo 'An example'; }
|
||||
|
||||
OR this
|
||||
|
||||
if($var = 'example')
|
||||
echo "An {$var}";
|
||||
|
||||
|
||||
Associative arrays
|
||||
-------------------------------------------------------------------------------
|
||||
Always use `[]` instead of `array()`. Associative arrays must be written in the
|
||||
following manner:
|
||||
|
||||
$array = [
|
||||
'var' => 'value',
|
||||
'var2' => 'value2'
|
||||
];
|
||||
|
||||
Note that spaces are preferred around the '=>'.
|
||||
|
||||
|
||||
A note about shorthands
|
||||
-------------------------------------------------------------------------------
|
||||
Some short hands are evil:
|
||||
|
||||
- Use the long format for `<?php`. Do NOT use `<?`.
|
||||
- Use the long format for `<?php` echo. Do NOT use `<?=`.
|
||||
|
||||
|
||||
Naming conventions
|
||||
-------------------------------------------------------------------------------
|
||||
Respect PSR2 first.
|
||||
|
||||
- Classes use PascalCase (e.g. MyClass).
|
||||
- Functions/Methods use camelCase (e.g. myFunction).
|
||||
- Variables use snake_case (e.g. my_variable).
|
||||
|
||||
A note on variable names, etc. It must be possible to understand what is meant
|
||||
without neccesarialy seeing it in context, because the code that calls something
|
||||
might not always make it clear.
|
||||
|
||||
So if you have something like:
|
||||
|
||||
$notice->post($contents);
|
||||
|
||||
Well I can easily tell what you're doing there because the names are straight-
|
||||
forward and clear.
|
||||
|
||||
Something like this:
|
||||
|
||||
foo->bar();
|
||||
|
||||
Is much less clear.
|
||||
|
||||
Also, whereever possible, avoid ambiguous terms. For example, don't use text
|
||||
as a term for a variable. Call back to "contents" above.
|
||||
|
||||
|
||||
Comparisons
|
||||
-------------------------------------------------------------------------------
|
||||
Always use symbol based comparison operators (&&, ||) instead of text based
|
||||
operators (AND, OR) as they are evaluated in different orders and at different
|
||||
speeds. This is will prevent any confusion or strange results.
|
||||
|
||||
|
||||
Use English
|
||||
-------------------------------------------------------------------------------
|
||||
All variables, classes, methods, functions and comments must be in English.
|
||||
Bad english is easier to work with than having to babelfish code to work out
|
||||
how it works.
|
||||
|
||||
|
||||
Encoding
|
||||
-------------------------------------------------------------------------------
|
||||
Files should be in UTF-8 encoding with UNIX line endings.
|
||||
|
||||
|
||||
No ending tag
|
||||
-------------------------------------------------------------------------------
|
||||
Files should not end with an ending php tag "?>". Any whitespace after the
|
||||
closing tag is sent to the browser and cause errors, so don't include them.
|
||||
|
||||
|
||||
Nesting Functions
|
||||
-------------------------------------------------------------------------------
|
||||
Avoid, if at all possible. When not possible, document the living daylights
|
||||
out of why you're nesting it. It's not always avoidable, but PHP 5 has a lot
|
||||
of obscure problems that come up with using nested functions.
|
||||
|
||||
If you must use a nested function, be sure to have robust error-handling.
|
||||
This is a must and submissions including nested functions that do not have
|
||||
robust error handling will be rejected and you'll be asked to add it.
|
||||
|
||||
|
||||
Scoping
|
||||
-------------------------------------------------------------------------------
|
||||
Properly enforcing scope of functions is something many PHP programmers don't
|
||||
do, but should.
|
||||
|
||||
In general:
|
||||
* Variables unique to a class should be protected and use interfacing to
|
||||
change them. This allows for input validation and making sure we don't have
|
||||
injection, especially when something's exposed to the API, that any program
|
||||
can use, and not all of them are going to be be safe and trusted.
|
||||
|
||||
* Variables not unique to a class should be validated prior to every call,
|
||||
which is why it's generally not a good idea to re-use stuff across classes
|
||||
unless there's significant performance gains to doing so.
|
||||
|
||||
* Classes should protect functions that they do not want overriden, but they
|
||||
should avoid protecting the constructor and destructor and related helper
|
||||
functions as this prevents proper inheritance.
|
||||
|
||||
|
||||
Typecasting
|
||||
-------------------------------------------------------------------------------
|
||||
PHP is a soft-typed language and it falls to us developers to make sure that
|
||||
we are using the proper inputs. Where ever possible use explicit type casting.
|
||||
Where it in't, you're going to have to make sure that you check all your
|
||||
inputs before you pass them.
|
||||
|
||||
All outputs should be cast as an explicit PHP type.
|
||||
|
||||
Not properly typecasting is a shooting offence. Soft types let programmers
|
||||
get away with a lot of lazy code, but lazy code is buggy code, and frankly, I
|
||||
don't want it in GNU social if it's going to be buggy.
|
||||
|
||||
|
||||
Consistent exception handling
|
||||
-------------------------------------------------------------------------------
|
||||
Consistency is key to good code to begin with, but it is especially important
|
||||
to be consistent with how we handle errors. GNU social has a variety of built-
|
||||
in exception classes. Use them, wherever it's possible and appropriate, and
|
||||
they will do the heavy lifting for you.
|
||||
|
||||
Additionally, ensure you clean up any and all records and variables that need
|
||||
cleanup in a function using try { } finally { } even if you do not plan on
|
||||
catching exceptions (why wouldn't you, though? That's silly.)
|
||||
|
||||
If you do not call an exception handler, you must, at a minimum, record errors
|
||||
to the log using common_log(level, message)
|
||||
|
||||
Ensure all possible control flows of a function have exception handling and
|
||||
cleanup, where appropriate. Don't leave endpoints with unhandled exceptions.
|
||||
Try not to leave something in an error state if it's avoidable.
|
||||
|
||||
|
||||
Return values
|
||||
-------------------------------------------------------------------------------
|
||||
All functions must return a value. Every single one. This is not optional.
|
||||
|
||||
If you are simply making a procedure call, for example as part of a helper
|
||||
function, then return boolean TRUE on success, and the exception on failure.
|
||||
|
||||
When returning the exception, return the whole nine yards, which is to say the
|
||||
actual PHP exception object, not just an error message.
|
||||
|
||||
All return values not the above should be type cast, and you should sanitize
|
||||
anything returned to ensure it fits into the cast. You might technically make
|
||||
an integer a string, for instance, but you should be making sure that integer
|
||||
SHOULD be a string, if you're returning it, and that it is a valid return
|
||||
value.
|
||||
|
||||
A vast majority of programming errors come down to not checking your inputs
|
||||
and outputs properly, so please try to do so as best and thoroughly as you can.
|
||||
|
||||
|
||||
Layout and Location of files
|
||||
-------------------------------------------------------------------------------
|
||||
`/actions/` contains files that determine what happens when something "happens":
|
||||
for instance, when someone favourites or repeats a notice. Code that is
|
||||
related to a "happening" should go here.
|
||||
|
||||
`/classes/` contains abstract definitions of certain "things" in the codebase
|
||||
such as a user or notice. If you're making a new "thing", it goes here.
|
||||
|
||||
`/lib/` is basically the back-end. Actions will call something in here to get
|
||||
stuff done usually, which in turn will probably manipulate information stored
|
||||
in one or more records represented by a class.
|
||||
|
||||
`/extlib/` is where external libraries are located. If you include a new
|
||||
external library, it goes here.
|
||||
|
||||
`/plugins/` This is a great way to modularize your own new features. If you want
|
||||
to create new core features for GNU social, it is probably best to create a
|
||||
module unless you absolutely must override or modify the core behaviours.
|
||||
@@ -1,32 +0,0 @@
|
||||
Submission Checklist
|
||||
================================================================================
|
||||
This document serves as a handy checklist for submitted merges and patches to
|
||||
the postActiv project. Following it isn't a gaurantee a patch will be accepted,
|
||||
but it will help you avoid common problems.
|
||||
|
||||
1. Ensure all code control paths in all functions return a value.
|
||||
|
||||
2. Ensure all exceptions are trapped in an exception class, or minimally,
|
||||
written to the log with common_log
|
||||
|
||||
3. Ensure the coding format standards are adhered to (see coding_standards.md)
|
||||
|
||||
4. Ensure that any new class that deals in public data has a corresponding new
|
||||
API endpoint.
|
||||
|
||||
5. Ensure that all new API endpoints sanitize inputs and outputs properly.
|
||||
|
||||
6. Ensure that your version of the code works with PHP 7 on a standard
|
||||
LAMP and LEMP stack (Linux+Apache+MariaDB+PHP and Linux+nginx+MariaDB+PHP)
|
||||
|
||||
7. If implementing new database functions, ensure they work with MariaDB
|
||||
and postgreSQL.
|
||||
|
||||
8. Ensure all data that federates does so properly and has mechanisms to
|
||||
catch and accomodate for federation transmission failure.
|
||||
|
||||
9. Ensure that nothing is left in an error state when it is avoidable.
|
||||
|
||||
10. Ensure that all code submitted is properly documented.
|
||||
|
||||
11. Ensure that there are no PHP Strict Standards or Parse errors in the code.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,355 +0,0 @@
|
||||
Plugin Development
|
||||
=======================
|
||||
|
||||
SamplePlugin.php
|
||||
-----------------------
|
||||
|
||||
Each plugin requires a main class to interact with the GNU social system.
|
||||
|
||||
The main class usually extends the Plugin class that comes with GNU social.
|
||||
|
||||
The class has standard-named methods that will be called when certain events
|
||||
happen in the code base. These methods have names like 'onX' where X is an
|
||||
event name (see EVENTS.txt for the list of available events). Event handlers
|
||||
have pre-defined arguments, based on which event they're handling. A typical
|
||||
event handler:
|
||||
|
||||
```php
|
||||
function onSomeEvent($paramA, &$paramB)
|
||||
{
|
||||
if ($paramA == 'jed') {
|
||||
throw new Exception(sprintf(_m("Invalid parameter %s"), $paramA));
|
||||
}
|
||||
$paramB = 'spock';
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Event Handlers
|
||||
-----------------------
|
||||
|
||||
Event handlers must return a Boolean value.
|
||||
|
||||
If they return false, all other event handlers for this event (in other plug-in)
|
||||
will be skipped, and in some cases the default processing for that event would
|
||||
be skipped. This is great for replacing the default action of an event.
|
||||
|
||||
If the handler returns true, processing of other event handlers and the default
|
||||
processing will continue. This is great for extending existing functionality.
|
||||
|
||||
If the handler throws an exception, processing will stop, and the exception's
|
||||
error will be shown to the user.
|
||||
|
||||
Installation
|
||||
------------------
|
||||
|
||||
To install a plugin (like this one), site admins add the following code to their
|
||||
config.php file:
|
||||
|
||||
```php
|
||||
addPlugin('Sample');
|
||||
```
|
||||
|
||||
Plugins must be installed in one of the following directories:
|
||||
|
||||
* local/plugins/{$pluginclass}.php
|
||||
* local/plugins/{$name}/{$pluginclass}.php
|
||||
* local/{$pluginclass}.php
|
||||
* local/{$name}/{$pluginclass}.php
|
||||
* plugins/{$pluginclass}.php
|
||||
* plugins/{$name}/{$pluginclass}.php
|
||||
|
||||
Here, `{$name}` is the name of the plugin, like 'Sample', and `{$pluginclass}`
|
||||
is the name of the main class, like 'SamplePlugin'. Plugins that are part of
|
||||
the main GNU social distribution go in 'plugins' and third-party or local ones
|
||||
go in 'local'.
|
||||
|
||||
Simple plugins can be implemented as a single module. Others are more complex
|
||||
and require additional modules; these should use their own directory, like
|
||||
'local/plugins/{$name}/'. All files related to the plugin, including images,
|
||||
JavaScript, CSS, external libraries or PHP modules should go in the plugin
|
||||
directory.
|
||||
|
||||
Plugin Configuration
|
||||
------------------
|
||||
|
||||
Plugins are configured using public instance attributes. To set their values,
|
||||
site administrators use this syntax:
|
||||
|
||||
```php
|
||||
addPlugin('Sample', ('attr1' => 'foo', 'attr2' => 'bar'));
|
||||
```
|
||||
|
||||
The same plugin class can be initialized multiple times with different arguments:
|
||||
|
||||
```php
|
||||
addPlugin('EmailNotify', array('sendTo' => 'evan@status.net'));
|
||||
addPlugin('EmailNotify', array('sendTo' => 'brionv@status.net'));
|
||||
```
|
||||
|
||||
```php
|
||||
class SamplePlugin extends Plugin
|
||||
{
|
||||
public $attr1 = null;
|
||||
public $attr2 = null;
|
||||
}
|
||||
```
|
||||
|
||||
Initialization
|
||||
------------------
|
||||
|
||||
Plugins overload this method to do any initialization they need, like connecting
|
||||
to remote servers or creating paths or so on. @return boolean hook value; true
|
||||
means continue processing, false means stop.
|
||||
|
||||
```php
|
||||
function initialize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Clean Up
|
||||
------------------
|
||||
|
||||
Plugins overload this method to do any cleanup they need, like disconnecting from
|
||||
remote servers or deleting temp files or so on.
|
||||
|
||||
```php
|
||||
function cleanup()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Database schema setup
|
||||
------------------
|
||||
|
||||
Plugins can add their own tables to the GNU social database. Plugins should use
|
||||
GNU social's schema interface to add or delete tables. The ensureTable() method
|
||||
provides an easy way to ensure a table's structure and availability.
|
||||
|
||||
By default, the schema is checked every time GNU social is run (say, when a Web
|
||||
page is hit). Admins can configure their systems to only check the schema when
|
||||
the checkschema.php script is run, greatly improving performance. However, they
|
||||
need to remember to run that script after installing or upgrading a plugin!
|
||||
|
||||
```php
|
||||
function onCheckSchema()
|
||||
{
|
||||
$schema = Schema::get();
|
||||
|
||||
// '''For storing user-submitted flags on profiles'''
|
||||
|
||||
$schema->ensureTable('user_greeting_count',
|
||||
array(new ColumnDef('user_id', 'integer', null,
|
||||
true, 'PRI'),
|
||||
new ColumnDef('greeting_count', 'integer')));
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Load related modules when needed
|
||||
------------------
|
||||
|
||||
Most non-trivial plugins will require extra modules to do their work. Typically
|
||||
these include data classes, action classes, widget classes, or external libraries.
|
||||
|
||||
This method receives a class name and loads the PHP file related to that class.
|
||||
By tradition, action classes typically have files named for the action, all
|
||||
lower-case. Data classes are in files with the data class name, initial letter
|
||||
capitalized.
|
||||
|
||||
Note that this method will be called for *all* overloaded classes, not just ones
|
||||
in this plugin! So, make sure to return true by default to let other plugins,
|
||||
and the core code, get a chance.
|
||||
|
||||
```php
|
||||
function onAutoload($cls)
|
||||
{
|
||||
$dir = dirname(__FILE__);
|
||||
|
||||
switch ($cls)
|
||||
{
|
||||
case 'HelloAction':
|
||||
include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
|
||||
return false;
|
||||
case 'User_greeting_count':
|
||||
include_once $dir . '/'.$cls.'.php';
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Map URLs to actions
|
||||
------------------
|
||||
|
||||
This event handler lets the plugin map URLs on the site to actions (and thus an
|
||||
action handler class). Note that the action handler class for an action will be
|
||||
named 'FoobarAction', where action = 'foobar'. The class must be loaded in the
|
||||
onAutoload() method.
|
||||
|
||||
```php
|
||||
function onRouterInitialized($m)
|
||||
{
|
||||
$m->connect('main/hello',
|
||||
array('action' => 'hello'));
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Modify the default menu to link to our custom action
|
||||
------------------
|
||||
|
||||
Using event handlers, it's possible to modify the default UI for pages almost
|
||||
without limit. In this method, we add a menu item to the default primary menu
|
||||
for the interface to link to our action.
|
||||
|
||||
Action Class
|
||||
------------------
|
||||
|
||||
The Action class provides a rich set of events to hook, as well as output methods.
|
||||
|
||||
```php
|
||||
function onEndPrimaryNav($action)
|
||||
{
|
||||
// '''common_local_url()''' gets the correct URL for the action name we provide
|
||||
|
||||
$action->menuItem(common_local_url('hello'),
|
||||
_m('Hello'), _m('A warm greeting'), false, 'nav_hello');
|
||||
return true;
|
||||
}
|
||||
|
||||
function onPluginVersion(&$versions)
|
||||
{
|
||||
$versions[] = array('name' => 'Sample',
|
||||
'version' => STATUSNET_VERSION,
|
||||
'author' => 'Brion Vibber, Evan Prodromou',
|
||||
'homepage' => 'http://example.org/plugin',
|
||||
'rawdescription' =>
|
||||
_m('A sample plugin to show basics of development for new hackers.'));
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
hello.php
|
||||
------------------
|
||||
|
||||
This section is taken directly from the 'hello.php'. ( plugins/Sample/hello.php )
|
||||
|
||||
Give a warm greeting to our friendly user.
|
||||
|
||||
This sample action shows some basic ways of doing output in an action class.
|
||||
|
||||
Action classes have several output methods that they override from the parent class.
|
||||
|
||||
```php
|
||||
class HelloAction extends Action
|
||||
{
|
||||
var $user = null;
|
||||
var $gc = null;
|
||||
}
|
||||
```
|
||||
|
||||
Take arguments for running
|
||||
------------------
|
||||
|
||||
This method is called first, and it lets the action class get all its arguments
|
||||
and validate them. It's also the time to fetch any relevant data from the database.
|
||||
|
||||
Action classes should run parent::prepare(array $args = []) as the first line
|
||||
of this method to make sure the default argument-processing happens.
|
||||
|
||||
```php
|
||||
function prepare(array $args = [])
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = common_current_user();
|
||||
|
||||
if (!empty($this->user)) {
|
||||
$this->gc = User_greeting_count::inc($this->user->id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Handle request
|
||||
------------------
|
||||
|
||||
This is the main method for handling a request. Note that most preparation
|
||||
should be done in the prepare() method; by the time handle() is called the
|
||||
action should be more or less ready to go.
|
||||
|
||||
```php
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$this->showPage();
|
||||
}
|
||||
```
|
||||
|
||||
Title of this page
|
||||
------------------
|
||||
|
||||
Override this method to show a custom title.
|
||||
|
||||
```php
|
||||
function title()
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
return _m('Hello');
|
||||
} else {
|
||||
return sprintf(_m('Hello, %s'), $this->user->nickname);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Show content in the content area
|
||||
------------------
|
||||
|
||||
The default GNU social page has a lot of decorations: menus, logos, tabs, all
|
||||
that jazz. This method is used to show content in the content area of the
|
||||
page; it's the main thing you want to overload. This method also demonstrates
|
||||
use of a plural localized string.
|
||||
|
||||
```php
|
||||
function showContent()
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->element('p', array('class' => 'greeting'),
|
||||
_m('Hello, stranger!'));
|
||||
} else {
|
||||
$this->element('p', array('class' => 'greeting'),
|
||||
sprintf(_m('Hello, %s'), $this->user->nickname));
|
||||
$this->element('p', array('class' => 'greeting_count'),
|
||||
sprintf(_m('I have greeted you %d time.',
|
||||
'I have greeted you %d times.',
|
||||
$this->gc->greeting_count),
|
||||
$this->gc->greeting_count));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Return true if read only.
|
||||
------------------
|
||||
|
||||
Some actions only read from the database; others read and write. The simple
|
||||
database load-balancer built into GNU social will direct read-only actions to
|
||||
database mirrors (if they are configured) and read-write actions to the master database.
|
||||
|
||||
This defaults to false to avoid data integrity issues, but you should make sure
|
||||
to overload it for performance gains.
|
||||
|
||||
```php
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
3
DOCUMENTATION/DEVELOPERS/defaults.md
Normal file
3
DOCUMENTATION/DEVELOPERS/defaults.md
Normal file
@@ -0,0 +1,3 @@
|
||||
In the `dev` environment, the default values for the config table are reloaded on each HTTP request
|
||||
|
||||
In case you want to override this, add `SOCIAL_NO_RELOAD_DEFAULTS=1` to your .env.local file
|
||||
1
DOCUMENTATION/DEVELOPERS/install.md
Symbolic link
1
DOCUMENTATION/DEVELOPERS/install.md
Symbolic link
@@ -0,0 +1 @@
|
||||
../../INSTALL.md
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
Plugins
|
||||
=======
|
||||
|
||||
GNU social supports a simple but
|
||||
powerful plugin architecture. Important events in the code are named,
|
||||
like 'StartNoticeSave', and other software can register interest
|
||||
in those events. When the events happen, the other software is called
|
||||
and has a choice of accepting or rejecting the events.
|
||||
|
||||
In the simplest case, you can add a function to config.php and use the
|
||||
Event::addHandler() function to hook an event:
|
||||
|
||||
function AddMyWebsiteLink($action)
|
||||
{
|
||||
$action->menuItem('http://mywebsite.net/', _('My web site'), _('Example web link'));
|
||||
return true;
|
||||
}
|
||||
|
||||
Event::addHandler('EndPrimaryNav', 'AddMyWebsiteLink');
|
||||
|
||||
This adds a menu item to the end of the main navigation menu. You can
|
||||
see the list of existing events, and parameters that handlers must
|
||||
implement, in EVENTS.txt.
|
||||
|
||||
The Plugin class in lib/plugin.php makes it easier to write more
|
||||
complex plugins. Sub-classes can just create methods named
|
||||
'onEventName', where 'EventName' is the name of the event (case
|
||||
matters!). These methods will be automatically registered as event
|
||||
handlers by the Plugin constructor (which you must call from your own
|
||||
class's constructor).
|
||||
|
||||
Several example plugins are included in the plugins/ directory. You
|
||||
can enable a plugin with the following line in config.php:
|
||||
|
||||
addPlugin('Example', array('param1' => 'value1',
|
||||
'param2' => 'value2'));
|
||||
|
||||
This will look for and load files named 'ExamplePlugin.php' or
|
||||
'Example/ExamplePlugin.php' either in the plugins/ directory (for
|
||||
plugins that ship with GNU social) or in the local/ directory (for
|
||||
plugins you write yourself or that you get from somewhere else) or
|
||||
local/plugins/.
|
||||
|
||||
Plugins are documented in their own directories.
|
||||
1
DOCUMENTATION/SYSTEM_ADMINISTRATORS/install.md
Symbolic link
1
DOCUMENTATION/SYSTEM_ADMINISTRATORS/install.md
Symbolic link
@@ -0,0 +1 @@
|
||||
../../INSTALL.md
|
||||
@@ -1,56 +0,0 @@
|
||||
Initial simple way to Webfinger enable your domain -- needs PHP.
|
||||
================================================================
|
||||
|
||||
This guide needs some updating, since it will only guide you to present
|
||||
XML data (while the curl command likely gives you JSON). The workaround
|
||||
is to simply make curl get 'webfinger.xml' instead, and/or have another
|
||||
file that contains JSON, but that requires editing the PHP file as well.
|
||||
|
||||
Step 1
|
||||
======
|
||||
|
||||
Put the 'dot-well-known' on your website, so it loads at:
|
||||
|
||||
https://example.com/.well-known/
|
||||
|
||||
(Remember the . at the beginning of this one, which is common practice
|
||||
for "hidden" files and why we have renamed it "dot-")
|
||||
|
||||
Step 2
|
||||
======
|
||||
|
||||
Edit the .well-known/host-meta file and replace "example.com" with the
|
||||
domain name you're hosting the .well-known directory on.
|
||||
|
||||
Using vim you can do this as a quick method:
|
||||
$ vim .well-known/host-meta [ENTER]
|
||||
:%s/example.com/domain.com/ [ENTER]
|
||||
:wq [ENTER]
|
||||
|
||||
Step 3
|
||||
======
|
||||
|
||||
For each user on your site, and this might only be you...
|
||||
|
||||
In the webfinger directory, make a copy of the example@example.com.xml file
|
||||
so that it's called (replace username and example.com with appropriate
|
||||
values, the domain name should be the same as you're "socialifying"):
|
||||
|
||||
username@example.com.xml
|
||||
|
||||
Then edit the file contents, replacing "social.example.com" with your
|
||||
GNU social instance's base path, and change the user ID number (and
|
||||
nickname for the FOAF link) to that of your account on your social
|
||||
site. If you don't know your user ID number, you can see this on your
|
||||
GNU social profile page by looking at the destination URLs in the
|
||||
Feeds links.
|
||||
|
||||
PROTIP: You can get the bulk of the contents (note the <Subject> element though)
|
||||
from curling down your real webfinger data:
|
||||
$ curl https://social.example.com/.well-known/webfinger?resource=acct:username@social.example.com
|
||||
|
||||
Finally
|
||||
=======
|
||||
|
||||
Using this method, though fiddly, you can now be @user@domain without
|
||||
the need for any prefixes for subdomains, etc.
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:hm="http://host-meta.net/xrd/1.0">
|
||||
<Link rel="lrdd" type="application/xrd+xml"
|
||||
template="https://example.com/.well-known/webfinger?resource={uri}"/>
|
||||
</XRD>
|
||||
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||
<Subject>acct:username@example.com</Subject>
|
||||
<Alias>acct:username@social.example.com</Alias>
|
||||
<Alias>https://social.example.com/user/1</Alias>
|
||||
<Link rel="http://webfinger.net/rel/profile-page"
|
||||
type="text/html"
|
||||
href="https://social.example.com/user/1"/>
|
||||
|
||||
<Link rel="http://schemas.google.com/g/2010#updates-from"
|
||||
type="application/atom+xml"
|
||||
href="https://social.example.com/api/statuses/user_timeline/1.atom"/>
|
||||
|
||||
<!-- Is this/was this ever supported?
|
||||
<Link rel="http://microformats.org/profile/hcard"
|
||||
type="text/html"
|
||||
href="https://social.example.com/hcard"/> -->
|
||||
|
||||
<Link rel="http://gmpg.org/xfn/11"
|
||||
type="text/html"
|
||||
href="https://social.example.com/user/1"/>
|
||||
|
||||
<Link rel="describedby"
|
||||
type="application/rdf+xml"
|
||||
href="https://social.example.com/username/foaf"/>
|
||||
|
||||
<Link rel="http://salmon-protocol.org/ns/salmon-replies"
|
||||
href="https://social.example.com/main/salmon/user/1"/>
|
||||
|
||||
<Link rel="http://salmon-protocol.org/ns/salmon-mention"
|
||||
href="https://social.example.com/main/salmon/user/1"/>
|
||||
|
||||
<Link rel="http://ostatus.org/schema/1.0/subscribe"
|
||||
template="https://social.example.com/main/ostatussub?profile={uri}"/>
|
||||
</XRD>
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* GNU social
|
||||
* Copyright (C) 2010, Free Software Foundation, 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/>.
|
||||
*/
|
||||
|
||||
|
||||
// basename should make sure we can't escape this directory
|
||||
$u = basename($_GET['resource']);
|
||||
|
||||
if (!strpos($u, '@')) {
|
||||
throw new Exception('Bad resource');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mb_strpos($u, 'acct:')===0) {
|
||||
$u = substr($u, 5);
|
||||
}
|
||||
|
||||
// Just to be a little bit safer, you know, with all the unicode stuff going on
|
||||
$u = filter_var($u, FILTER_SANITIZE_EMAIL);
|
||||
|
||||
$f = $u . ".xml";
|
||||
|
||||
if (file_exists($f)) {
|
||||
header('Content-Disposition: attachment; filename="'.urlencode($f).'"');
|
||||
header('Content-type: application/xrd+xml');
|
||||
echo file_get_contents($f);
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
Upgrading
|
||||
=========
|
||||
|
||||
GNU social 1.1.x to GNU social 1.2.x
|
||||
------------------------------------
|
||||
|
||||
If you are tracking the GNU social git repository, we currently recommend
|
||||
using the "master" branch (or nightly if you want to use latest features)
|
||||
and follow this procedure:
|
||||
|
||||
0. Backup your data. The StatusNet upgrade discussions below have some
|
||||
guidelines to back up the database and files (mysqldump and rsync).
|
||||
|
||||
MAKE SURE YOU ARE THE SAME USER THAT RUNS THE PHP FILES WHILE PERFORMING
|
||||
THE COMMANDS BELOW (I usually prepend the commands with 'sudo -u social')
|
||||
|
||||
1. Stop your queue daemons (you can run this command even if you do not
|
||||
use the queue daemons):
|
||||
$ bash scripts/stopdaemons.sh
|
||||
|
||||
2. Run the command to fetch the latest sourcecode:
|
||||
$ git pull
|
||||
|
||||
If you are not using git we recommend following the instructions below
|
||||
for upgrading "StatusNet 1.1.x to GNU social 1.2.x" as they are similar.
|
||||
|
||||
3. Run the upgrade script:
|
||||
$ php scripts/upgrade.php
|
||||
|
||||
The upgrade script will likely take a long time because it will
|
||||
upgrade the tables to another character encoding and make other
|
||||
automated upgrades. Make sure it ends without errors. If you get
|
||||
errors, create a new task on https://git.gnu.io/gnu/gnu-social/issues
|
||||
|
||||
4. Start your queue daemons again (you can run this command even if you
|
||||
do not use the queue daemons):
|
||||
$ bash scripts/startdaemons.sh
|
||||
|
||||
5. Report any issues at https://git.gnu.io/gnu/gnu-social/issues
|
||||
|
||||
If you are using ssh keys to log in to your server, you can make this
|
||||
procedure pretty painless (assuming you have automated backups already).
|
||||
Make sure you "cd" into the correct directory (in this case "htdocs")
|
||||
and use the correct login@hostname combo:
|
||||
$ ssh social@domain.example 'cd htdocs
|
||||
&& bash scripts/stopdaemons.sh
|
||||
&& git pull
|
||||
&& time php scripts/upgrade.php
|
||||
&& bash scripts/startdaemons.sh'
|
||||
|
||||
StatusNet 1.1.x to GNU social 1.2.x
|
||||
-----------------------------------
|
||||
|
||||
We cannot support migrating from any other version of StatusNet than
|
||||
1.1.1. If you are running a StatusNet version lower than this, please
|
||||
follow the upgrade procedures for each respective StatusNet version.
|
||||
|
||||
You are now running StatusNet 1.1.1 and want to migrate to GNU social
|
||||
1.2.x. Beware there may be changes in minimum required version of PHP
|
||||
and the modules required, so review the INSTALL file (php5-intl is a
|
||||
newly added dependency for example).
|
||||
|
||||
* Before you begin: Make backups. Always make backups. Of your entire
|
||||
directory structure and the database too. All tables. All data. Alles.
|
||||
|
||||
0. Make a backup of everything. To backup the database, you can use a
|
||||
variant of this command (you will be prompted for the database password):
|
||||
$ mysqldump -u dbuser -p dbname > social-backup.sql
|
||||
|
||||
1. Stop your queue daemons 'bash scripts/stopdaemons.sh' should do it.
|
||||
Not everyone runs queue daemons, but the above command won't hurt.
|
||||
|
||||
2. Unpack your GNU social code to a fresh directory. You can do this
|
||||
by cloning our git repository:
|
||||
$ git clone https://git.gnu.io/gnu/gnu-social.git gnusocial
|
||||
|
||||
3. Synchronize your local files to the GNU social directory. These
|
||||
will be the local files such as avatars, config and files:
|
||||
|
||||
avatar/*
|
||||
file/*
|
||||
local/*
|
||||
.htaccess
|
||||
config.php
|
||||
|
||||
This command will point you in the right direction on how to do it:
|
||||
$ rsync -avP statusnet/{.htaccess,avatar,file,local,config.php} gnusocial/
|
||||
|
||||
4. Replace your old StatusNet directory with the new GNU social
|
||||
directory in your webserver root.
|
||||
|
||||
5. Run the upgrade script: 'php scripts/upgrade.php'
|
||||
The upgrade script will likely take a long time because it will
|
||||
upgrade the tables to another character encoding and make other
|
||||
automated upgrades. Make sure it ends without errors. If you get
|
||||
errors, create a new task on https://git.gnu.io/gnu/gnu-social/issues
|
||||
|
||||
6. Start your queue daemons: 'bash scripts/startdaemons.sh'
|
||||
|
||||
7. Report any issues at https://git.gnu.io/gnu/gnu-social/issues
|
||||
@@ -1,55 +0,0 @@
|
||||
### GNU social "fancy URL" setup
|
||||
#
|
||||
# Change the "RewriteBase" in the new .htaccess file to be the URL path
|
||||
# to your GNU Social installation on your server. Typically this will
|
||||
# be the path to your GNU Social directory relative to your Web root.
|
||||
# If you are installing it in the root directory, leave it as '/'.
|
||||
#
|
||||
# If it doesn't work, double-check that AllowOverride for the GNU Social
|
||||
# directory is 'All' in your Apache configuration file. This can be
|
||||
# * /etc/apache2/apache2.conf (generic)
|
||||
# * /etc/apache2/sites-available/default(on Debian and Ubuntu)
|
||||
# * ...many other variations depending on distribution...
|
||||
#
|
||||
# See the Apache documentation for .htaccess files for more details:
|
||||
# https://httpd.apache.org/docs/2.4/howto/htaccess.html
|
||||
#
|
||||
# Also, check that mod_rewrite is installed and enabled:
|
||||
# https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html
|
||||
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
|
||||
# NOTE: change this to your actual GNU social base URL path,
|
||||
# minus the domain part:
|
||||
#
|
||||
# https://social.example.com/ => /
|
||||
# https://example.com/social/ => /social/
|
||||
#
|
||||
RewriteBase /
|
||||
#RewriteBase /mublog/
|
||||
|
||||
## Uncomment these if having trouble with API authentication
|
||||
## when PHP is running in CGI or FastCGI mode.
|
||||
#
|
||||
#RewriteCond %{HTTP:Authorization} ^(.*)
|
||||
#RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule (.*) index.php?p=$1 [L,QSA]
|
||||
|
||||
## You can also use PATHINFO by using this RewriteRule instead:
|
||||
# RewriteRule (.*) index.php/$1 [L,QSA]
|
||||
</IfModule>
|
||||
|
||||
<FilesMatch "\.(ini)">
|
||||
<IfVersion < 2.3>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.3>
|
||||
Require all denied
|
||||
</IfVersion>
|
||||
</FilesMatch>
|
||||
@@ -1,28 +0,0 @@
|
||||
# This is completely optional, but if you're running a site with
|
||||
# ssl="always" configured, then you might as well redirect any of
|
||||
# your stray HTTP visitors to HTTPS.
|
||||
#
|
||||
#$HTTP["scheme"] == "http" {
|
||||
# $HTTP["host"] =~ "^(social\.example\.com)$" {
|
||||
# url.redirect = ( "^\/?(.*)" => "https://%1/$1" )
|
||||
# server.name = "%1"
|
||||
# }
|
||||
#}
|
||||
|
||||
# If you're using vhosts, you should have per-vhost server.document-root
|
||||
# settings too! Read how in the respective alternative vhost modules.
|
||||
#$HTTP["host"] =~ "^social\.example\.com$" {
|
||||
|
||||
# NOTE: configure fastcgi/cgi/fpm here if you're using per-user cgi/fpm
|
||||
# fastcgi.server += ( ".php" =>
|
||||
# ( "localhost" => (
|
||||
# "host" => "127.0.0.1",
|
||||
# "port" => "9000"
|
||||
# ))
|
||||
# )
|
||||
|
||||
dir-listing.activate = "disable"
|
||||
|
||||
# Make sure "mod_rewrite" is enabled in server.modules
|
||||
url.rewrite-if-not-file = ( "^/(.*)$" => "/index.php/$1" )
|
||||
#}
|
||||
@@ -1,89 +0,0 @@
|
||||
server {
|
||||
listen [::]:80;
|
||||
listen 80;
|
||||
|
||||
# FIXME: Change domain name here (and also make sure you do the same in the next 'server' section)
|
||||
server_name social.example.org;
|
||||
|
||||
# redirect all traffic to HTTPS
|
||||
rewrite ^ https://$host$request_uri? permanent;
|
||||
}
|
||||
|
||||
server {
|
||||
# HTTPS is mandatory on GNU social unless you are using Tor network. Seriously.
|
||||
# Set it up with a cert (any cert) before you run the install.
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
|
||||
# Root
|
||||
# FIXME: Change the path below to where you installed GNU social
|
||||
root /path/to/gnusocial/root;
|
||||
|
||||
# Server name
|
||||
# FIXME: Change "social.example.org" to your site's domain name
|
||||
server_name social.example.org;
|
||||
|
||||
# SSL
|
||||
# FIXME: Change the paths to setup your SSL key/cert. See https://cipherli.st/ for more information
|
||||
ssl_certificate ssl/certs/social.example.org.crt;
|
||||
ssl_certificate_key ssl/private/social.example.org.key;
|
||||
|
||||
# Index
|
||||
index index.php;
|
||||
|
||||
# PHP
|
||||
location ~ ^/(index|install)\.php$ {
|
||||
#location ^~ /index.php {
|
||||
include fastcgi_params;
|
||||
include snippets/fastcgi-php.conf;
|
||||
|
||||
fastcgi_pass unix:/run/php/php-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||
}
|
||||
|
||||
# Don't allow any PHP file other than index.php to be executed
|
||||
# This will ensure that nor config.php nor plugin files with eventual hardcoded security information are downloadable
|
||||
# And this is better than allowing php files to be executed in case of forgotten `if (!defined('GNUSOCIAL')) { exit(1); }`
|
||||
location ~ \.php$ {
|
||||
deny all;
|
||||
}
|
||||
|
||||
# Location
|
||||
location / {
|
||||
try_files $uri $uri/ @index_handler;
|
||||
}
|
||||
|
||||
# Fancy URLs
|
||||
error_page 404 @index_handler;
|
||||
location @index_handler {
|
||||
rewrite ^(.*)$ /index.php?p=$1 last;
|
||||
}
|
||||
|
||||
# Restrict access that is unnecessary anyway
|
||||
location ~ /\.(ht|git) {
|
||||
deny all;
|
||||
}
|
||||
|
||||
#
|
||||
# Hardening (optional)
|
||||
#
|
||||
# add_header Strict-Transport-Security "max-age=15768000; preload;";
|
||||
# add_header X-Content-Type-Options nosniff;
|
||||
# add_header Referrer-Policy strict-origin-when-cross-origin;
|
||||
# add_header Content-Security-Policy "default-src 'self' 'unsafe-inline'; frame-ancestors 'self'; form-action 'self'; style-src 'self' 'unsafe-inline'; img-src * blob: data:;";
|
||||
# add_header X-Permitted-Cross-Domain-Policies none;
|
||||
# add_header X-Robots-Tag all; # Not really hardening, just here for strictness purposes
|
||||
#
|
||||
# client_max_body_size 15M;
|
||||
# client_body_buffer_size 128k;
|
||||
# gzip_vary on;
|
||||
#
|
||||
# location ~* \.(?:css|js|woff|svg|gif|png|webp|ttf|ico|jpe?g)$ {
|
||||
# gzip on;
|
||||
# gzip_comp_level 4;
|
||||
# add_header Cache-Control "public";
|
||||
# expires 30d;
|
||||
# access_log off;
|
||||
# log_not_found off;
|
||||
# }
|
||||
}
|
||||
466
INSTALL.md
466
INSTALL.md
@@ -1,463 +1,5 @@
|
||||
TABLE OF CONTENTS
|
||||
=================
|
||||
* Prerequisites
|
||||
- PHP modules
|
||||
- Better performance
|
||||
* Installation
|
||||
- Getting it up and running
|
||||
- Fancy URLs
|
||||
- Themes
|
||||
- Private
|
||||
* Extra features
|
||||
- Sphinx
|
||||
- SMS
|
||||
- Translation
|
||||
- Queues and daemons
|
||||
* After installation
|
||||
- Backups
|
||||
- Upgrading
|
||||
* Additional configuration
|
||||
GNU social
|
||||
=====
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
PHP modules
|
||||
-----------
|
||||
|
||||
The following software packages are *required* for this software to
|
||||
run correctly.
|
||||
|
||||
- PHP 7+ PHP7.x is also supported.
|
||||
- MariaDB 5+ MariaDB 10.x is also supported.
|
||||
- Web server Apache, lighttpd and nginx will all work. CGI mode is
|
||||
recommended and also some variant of 'suexec' (or a
|
||||
proper setup php-fpm pool)
|
||||
NOTE: mod_rewrite or its equivalent is extremely useful.
|
||||
|
||||
Your PHP installation must include the following PHP extensions for a
|
||||
functional setup of GNU social:
|
||||
|
||||
- openssl (compiled in for Debian, enabled manually in Arch Linux)
|
||||
- php-curl Fetching files by HTTP.
|
||||
- php-exif Exchangeable image information.
|
||||
- php-gd Image manipulation (scaling).
|
||||
- php-intl Internationalization support (transliteration et al).
|
||||
- php-json For WebFinger lookups and more.
|
||||
- php-mbstring String manipulation
|
||||
- php-mysql The native driver for MariaDB connections.
|
||||
- php-gmp For Salmon signatures (part of OStatus)
|
||||
- php-bcmath Arbitrary Precision Mathematics
|
||||
- php-opcache Improved PHP performance by precompilation
|
||||
- php-readline For interactive scripts
|
||||
- php-xml XML parser
|
||||
- php-ds Faster data structures
|
||||
|
||||
NOTE: Some distros require manual enabling in the relevant php.ini for some modules.
|
||||
|
||||
Better performance
|
||||
------------------
|
||||
|
||||
For some functionality, you will also need the following extensions:
|
||||
|
||||
- opcache Improves performance a _lot_. Included in PHP, must be
|
||||
enabled manually in php.ini for most distributions. Find
|
||||
and set at least: opcache.enable=1
|
||||
- mailparse Efficient parsing of email requires this extension.
|
||||
Submission by email or SMS-over-email uses this.
|
||||
- sphinx A client for the sphinx server, an alternative to MySQL
|
||||
or Postgresql fulltext search. You will also need a
|
||||
Sphinx server to serve the search queries.
|
||||
- gettext For multiple languages. Default on many PHP installs;
|
||||
will be emulated if not present.
|
||||
- exif For thumbnails to be properly oriented.
|
||||
- php-ds For faster data structures; will be emulated if not present.
|
||||
|
||||
You may also experience better performance from your site if you configure
|
||||
a PHP cache/accelerator. Most distributions come with "opcache" support.
|
||||
Enable it in your php.ini where it is documented together with its settings.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Getting it up and running
|
||||
-------------------------
|
||||
|
||||
Installing the basic GNU Social web component is relatively easy,
|
||||
especially if you've previously installed PHP/MariaDB packages.
|
||||
|
||||
1. Unpack the tarball you downloaded on your Web server. Usually a
|
||||
command like this will work:
|
||||
|
||||
tar zxf gnusocial-*.tar.gz
|
||||
|
||||
...which will make a gnusocial-x.y.z subdirectory in your current
|
||||
directory. (If you don't have shell access on your Web server, you
|
||||
may have to unpack the tarball on your local computer and FTP the
|
||||
files to the server.)
|
||||
|
||||
2. Move the tarball to a directory of your choosing in your Web root
|
||||
directory. Usually something like this will work:
|
||||
|
||||
mv gnusocial-x.y.z /var/www/gnusocial
|
||||
|
||||
This will often make your GNU Social instance available in the gnusocial
|
||||
path of your server, like "http://example.net/gnusocial". "social" or
|
||||
"blog" might also be good path names. If you know how to configure
|
||||
virtual hosts on your web server, you can try setting up
|
||||
"http://social.example.net/" or the like.
|
||||
|
||||
If you have "rewrite" support on your webserver, and you should,
|
||||
then please enable this in order to make full use of your site. This
|
||||
will enable "Fancy URL" support, which you can read more about if you
|
||||
scroll down a bit in this document.
|
||||
|
||||
3. Make your target directory writeable by the Web server, please note
|
||||
however that 'a+w' will give _all_ users write access and securing the
|
||||
webserver is not within the scope of this document.
|
||||
|
||||
chmod a+w /var/www/gnusocial/
|
||||
|
||||
On some systems, this will work as a more secure alternative:
|
||||
|
||||
chgrp www-data /var/www/gnusocial/
|
||||
chmod g+w /var/www/gnusocial/
|
||||
|
||||
If your Web server runs as another user besides "www-data", try
|
||||
that user's default group instead. As a last resort, you can create
|
||||
a new group like "gnusocial" and add the Web server's user to the group.
|
||||
|
||||
4. Create a database to hold your site data. Something like this
|
||||
should work (you will be prompted for your database password):
|
||||
|
||||
mysqladmin -u "root" -p create social
|
||||
|
||||
Note that GNU Social should have its own database; you should not share
|
||||
the database with another program. You can name it whatever you want,
|
||||
though.
|
||||
|
||||
(If you don't have shell access to your server, you may need to use
|
||||
a tool like phpMyAdmin to create a database. Check your hosting
|
||||
service's documentation for how to create a new MariaDB database.)
|
||||
|
||||
5. Create a new database account that GNU Social will use to access the
|
||||
database. If you have shell access, this will probably work from the
|
||||
MariaDB shell:
|
||||
|
||||
GRANT ALL on social.*
|
||||
TO 'social'@'localhost'
|
||||
IDENTIFIED BY 'agoodpassword';
|
||||
|
||||
You should change the user identifier 'social' and 'agoodpassword'
|
||||
to your preferred new database username and password. You may want to
|
||||
test logging in to MariaDB as this new user.
|
||||
|
||||
6. In a browser, navigate to the GNU Social install script; something like:
|
||||
|
||||
https://social.example.net/install.php
|
||||
|
||||
Enter the database connection information and your site name. The
|
||||
install program will configure your site and install the initial,
|
||||
almost-empty database.
|
||||
|
||||
7. You should now be able to navigate to your social site's main directory
|
||||
and see the "Public Timeline", which will probably be empty. You can
|
||||
now register new user, post some notices, edit your profile, etc.
|
||||
|
||||
Fancy URLs
|
||||
----------
|
||||
|
||||
By default, GNU Social will use URLs that include the main PHP program's
|
||||
name in them. For example, a user's home profile might be found at either
|
||||
of these URLS depending on the webserver's configuration and capabilities:
|
||||
|
||||
https://social.example.net/index.php/fred
|
||||
https://social.example.net/index.php?p=fred
|
||||
|
||||
It's possible to configure the software to use fancy URLs so it looks like
|
||||
this instead:
|
||||
|
||||
https://social.example.net/fred
|
||||
|
||||
These "fancy URLs" are more readable and memorable for users. To use
|
||||
fancy URLs, you must either have Apache 2.x with .htaccess enabled and
|
||||
mod_rewrite enabled, -OR- know how to configure "url redirection" in
|
||||
your server (like lighttpd or nginx).
|
||||
|
||||
1. See the instructions for each respective webserver software:
|
||||
* For Apache, inspect the "htaccess.sample" file and save it as
|
||||
".htaccess" after making any necessary modifications. Our sample
|
||||
file is well commented.
|
||||
* For lighttpd, inspect the lighttpd.conf.example file and apply the
|
||||
appropriate changes in your virtualhost configuration for lighttpd.
|
||||
* For nginx, inspect the nginx.conf.sample file and apply the appropriate
|
||||
changes.
|
||||
* For other webservers, we gladly accept contributions of
|
||||
server configuration examples.
|
||||
|
||||
2. Assuming your webserver is properly configured and have its settings
|
||||
applied (remember to reload/restart it), you can add this to your
|
||||
GNU social's config.php file:
|
||||
$config['site']['fancy'] = true;
|
||||
|
||||
You should now be able to navigate to a "fancy" URL on your server,
|
||||
like:
|
||||
|
||||
https://social.example.net/main/register
|
||||
|
||||
Themes
|
||||
------
|
||||
|
||||
As of right now, your ability change the theme is limited to CSS
|
||||
stylesheets and some image files; you can't change the HTML output,
|
||||
like adding or removing menu items, without the help of a plugin.
|
||||
|
||||
You can choose a theme using the $config['site']['theme'] element in
|
||||
the config.php file. See below for details.
|
||||
|
||||
You can add your own theme by making a sub-directory of the 'theme'
|
||||
subdirectory with the name of your theme. Each theme can have the
|
||||
following files:
|
||||
|
||||
display.css: a CSS2 file for "default" styling for all browsers.
|
||||
logo.png: a logo image for the site.
|
||||
default-avatar-profile.png: a 96x96 pixel image to use as the avatar for
|
||||
users who don't upload their own.
|
||||
default-avatar-stream.png: Ditto, but 48x48. For streams of notices.
|
||||
default-avatar-mini.png: Ditto ditto, but 24x24. For subscriptions
|
||||
listing on profile pages.
|
||||
|
||||
You may want to start by copying the files from the default theme to
|
||||
your own directory.
|
||||
|
||||
Private
|
||||
-------
|
||||
|
||||
A GNU social node can be configured as "private", which means it will not
|
||||
federate with other nodes in the network. It is not a recommended method
|
||||
of using GNU social and we cannot at the current state of development
|
||||
guarantee that there are no leaks (what a public network sees as features,
|
||||
private sites will likely see as bugs).
|
||||
|
||||
Private nodes are however an easy way to easily setup collaboration and
|
||||
image sharing within a workgroup or a smaller community where federation
|
||||
is not a desired feature. Also, it is possible to change this setting and
|
||||
instantly gain full federation features.
|
||||
|
||||
Access to file attachments can also be restricted to logged-in users only:
|
||||
|
||||
1. Add a directory outside the web root where your file uploads will be
|
||||
stored. Use this command as an initial guideline to create it:
|
||||
|
||||
mkdir /var/www/gnusocial-files
|
||||
|
||||
2. Make the file uploads directory writeable by the web server. An
|
||||
insecure way to do this is (to do it properly, read up on UNIX file
|
||||
permissions and configure your webserver accordingly):
|
||||
|
||||
chmod a+x /var/www/gnusocial-files
|
||||
|
||||
3. Tell GNU social to use this directory for file uploads. Add a line
|
||||
like this to your config.php:
|
||||
|
||||
$config['attachments']['dir'] = '/var/www/gnusocial-files';
|
||||
|
||||
Extra features
|
||||
==============
|
||||
|
||||
Sphinx
|
||||
------
|
||||
|
||||
To use a Sphinx server to search users and notices, you'll need to
|
||||
enable the SphinxSearch plugin. Add to your config.php:
|
||||
|
||||
addPlugin('SphinxSearch');
|
||||
$config['sphinx']['server'] = 'searchhost.local';
|
||||
|
||||
You also need to install, compile and enable the sphinx pecl extension for
|
||||
php on the client side, which itself depends on the sphinx development files.
|
||||
|
||||
See plugins/SphinxSearch/README for more details and server setup.
|
||||
|
||||
SMS
|
||||
---
|
||||
|
||||
StatusNet supports a cheap-and-dirty system for sending update messages
|
||||
to mobile phones and for receiving updates from the mobile. Instead of
|
||||
sending through the SMS network itself, which is costly and requires
|
||||
buy-in from the wireless carriers, it simply piggybacks on the email
|
||||
gateways that many carriers provide to their customers. So, SMS
|
||||
configuration is essentially email configuration.
|
||||
|
||||
Each user sends to a made-up email address, which they keep a secret.
|
||||
Incoming email that is "From" the user's SMS email address, and "To"
|
||||
the users' secret email address on the site's domain, will be
|
||||
converted to a notice and stored in the DB.
|
||||
|
||||
For this to work, there *must* be a domain or sub-domain for which all
|
||||
(or most) incoming email can pass through the incoming mail filter.
|
||||
|
||||
1. Run the SQL script carrier.sql in your StatusNet database. This will
|
||||
usually work:
|
||||
|
||||
mysql -u "statusnetuser" --password="statusnetpassword" statusnet < db/carrier.sql
|
||||
|
||||
This will populate your database with a list of wireless carriers
|
||||
that support email SMS gateways.
|
||||
|
||||
2. Make sure the maildaemon.php file is executable:
|
||||
|
||||
chmod +x scripts/maildaemon.php
|
||||
|
||||
Note that "daemon" is kind of a misnomer here; the script is more
|
||||
of a filter than a daemon.
|
||||
|
||||
2. Edit /etc/aliases on your mail server and add the following line:
|
||||
|
||||
*: /path/to/statusnet/scripts/maildaemon.php
|
||||
|
||||
3. Run whatever code you need to to update your aliases database. For
|
||||
many mail servers (Postfix, Exim, Sendmail), this should work:
|
||||
|
||||
newaliases
|
||||
|
||||
You may need to restart your mail server for the new database to
|
||||
take effect.
|
||||
|
||||
4. Set the following in your config.php file:
|
||||
|
||||
$config['mail']['domain'] = 'yourdomain.example.net';
|
||||
|
||||
Translations
|
||||
------------
|
||||
|
||||
For info on helping with translations, see the platform currently in use
|
||||
for translations: https://www.transifex.com/projects/p/gnu-social/
|
||||
|
||||
Translations use the gettext system <http://www.gnu.org/software/gettext/>.
|
||||
If you for some reason do not wish to sign up to the Transifex service,
|
||||
you can review the files in the "locale/" sub-directory of GNU social.
|
||||
Each plugin also has its own translation files.
|
||||
|
||||
To get your own site to use all the translated languages, and you are
|
||||
tracking the git repo, you will need to install at least 'gettext' on
|
||||
your system and then run:
|
||||
$ make translations
|
||||
|
||||
Queues and daemons
|
||||
------------------
|
||||
|
||||
Some activities that StatusNet needs to do, like broadcast OStatus, SMS,
|
||||
XMPP messages and TwitterBridge operations, can be 'queued' and done by
|
||||
off-line bots instead.
|
||||
|
||||
Two mechanisms are available to achieve offline operations:
|
||||
|
||||
* New embedded OpportunisticQM plugin, which is enabled by default
|
||||
* Legacy queuedaemon script, which can be enabled via config file.
|
||||
|
||||
### OpportunisticQM plugin
|
||||
|
||||
This plugin is enabled by default. It tries its best to do background
|
||||
jobs during regular HTTP requests, like API or HTML pages calls.
|
||||
|
||||
Since queueing system is enabled by default, notices to be broadcasted
|
||||
will be stored, by default, into DB (table queue_item).
|
||||
|
||||
Whenever it has time, OpportunisticQM will try to handle some of them.
|
||||
|
||||
This is a good solution whether you:
|
||||
|
||||
* have no access to command line (shared hosting)
|
||||
* do not want to deal with long-running PHP processes
|
||||
* run a low traffic GNU social instance
|
||||
|
||||
In other case, you really should consider enabling the queuedaemon for
|
||||
performance reasons. Background daemons are necessary anyway if you wish
|
||||
to use the Instant Messaging features such as communicating via XMPP.
|
||||
|
||||
### queuedaemon
|
||||
|
||||
If you want to use legacy queuedaemon, you must be able to run
|
||||
long-running offline processes, either on your main Web server or on
|
||||
another server you control. (Your other server will still need all the
|
||||
above prerequisites, with the exception of Apache.) Installing on a
|
||||
separate server is probably a good idea for high-volume sites.
|
||||
|
||||
1. You'll need the "CLI" (command-line interface) version of PHP
|
||||
installed on whatever server you use.
|
||||
|
||||
Modern PHP versions in some operating systems have disabled functions
|
||||
related to forking, which is required for daemons to operate. To make
|
||||
this work, make sure that your php-cli config (/etc/php5/cli/php.ini)
|
||||
does NOT have these functions listed under 'disable_functions':
|
||||
|
||||
* pcntl_fork, pcntl_wait, pcntl_wifexited, pcntl_wexitstatus,
|
||||
pcntl_wifsignaled, pcntl_wtermsig
|
||||
|
||||
Other recommended settings for optimal performance are:
|
||||
* mysqli.allow_persistent = On
|
||||
* mysqli.reconnect = On
|
||||
|
||||
2. If you're using a separate server for queues, install StatusNet
|
||||
somewhere on the server. You don't need to worry about the
|
||||
.htaccess file, but make sure that your config.php file is close
|
||||
to, or identical to, your Web server's version.
|
||||
|
||||
3. In your config.php files (on the server where you run the queue
|
||||
daemon), set the following variable:
|
||||
|
||||
$config['queue']['daemon'] = true;
|
||||
|
||||
You may also want to look at the 'Queues and Daemons' section in
|
||||
this file for more background processing options.
|
||||
|
||||
4. On the queues server, run the command scripts/startdaemons.sh.
|
||||
|
||||
This will run the queue handlers:
|
||||
|
||||
* queuedaemon.php - polls for queued items for inbox processing and
|
||||
pushing out to OStatus, SMS, XMPP, etc.
|
||||
* imdaemon.php - if an IM plugin is enabled (like XMPP)
|
||||
* other daemons, like TwitterBridge ones, that you may have enabled
|
||||
|
||||
These daemons will automatically restart in most cases of failure
|
||||
including memory leaks (if a memory_limit is set), but may still die
|
||||
or behave oddly if they lose connections to the XMPP or queue servers.
|
||||
|
||||
It may be a good idea to use a daemon-monitoring service, like 'monit',
|
||||
to check their status and keep them running.
|
||||
|
||||
All the daemons write their process IDs (pids) to /var/run/ by
|
||||
default. This can be useful for starting, stopping, and monitoring the
|
||||
daemons. If you are running multiple sites on the same machine, it will
|
||||
be necessary to avoid collisions of these PID files by setting a site-
|
||||
specific directory in config.php:
|
||||
|
||||
$config['daemon']['piddir'] = __DIR__ . '/../run/';
|
||||
|
||||
It is also possible to use a STOMP server instead of our kind of hacky
|
||||
home-grown DB-based queue solution. This is strongly recommended for
|
||||
best response time, especially when using XMPP.
|
||||
|
||||
After installation
|
||||
==================
|
||||
|
||||
Backups
|
||||
-------
|
||||
|
||||
There is no built-in system for doing backups in GNU social. You can make
|
||||
backups of a working StatusNet system by backing up the database and
|
||||
the Web directory. To backup the database use mysqldump <https://mariadb.com/kb/en/mariadb/mysqldump/>
|
||||
and to backup the Web directory, try tar.
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
|
||||
Upgrading is strongly recommended to stay up to date with security fixes
|
||||
and new features. For instructions on how to upgrade GNU social code,
|
||||
please see the UPGRADE file.
|
||||
|
||||
Additional configuration
|
||||
------------------------
|
||||
|
||||
Please refer to DOCUMENTATION/SYSTEM_ADMINISTRATORS/CONFIGURE for information.
|
||||
GNU social is a federated social network. For documentation, visit
|
||||
https://docs.gnusocial.rocks/ or view the files under docs/
|
||||
|
||||
35
Makefile
35
Makefile
@@ -1,18 +1,31 @@
|
||||
# Warning: do not transform tabs to spaces in this file.
|
||||
DIR=$(strip $(notdir $(CURDIR))) # Seems a bit hack-ish, but `basename` works differently
|
||||
|
||||
all : translations
|
||||
.PHONY:
|
||||
@if ! docker info > /dev/null; then echo "Docker does not seem to be running"; exit 1; fi
|
||||
|
||||
core_mo = $(patsubst %.po,%.mo,$(wildcard locale/*/LC_MESSAGES/statusnet.po))
|
||||
plugin_mo = $(patsubst %.po,%.mo,$(wildcard plugins/*/locale/*/LC_MESSAGES/*.po))
|
||||
up: .PHONY
|
||||
docker-compose up -d
|
||||
|
||||
translations : $(core_mo) $(plugin_mo)
|
||||
down: .PHONY
|
||||
docker-compose down
|
||||
|
||||
clean :
|
||||
rm -f $(core_mo) $(plugin_mo)
|
||||
redis-shell:
|
||||
docker exec -it $(strip $(DIR))_redis_1 sh -c 'redis-cli'
|
||||
|
||||
updatepo :
|
||||
php scripts/update_po_templates.php --all
|
||||
php-repl: .PHONY
|
||||
docker exec -it $(strip $(DIR))_php_1 sh -c '/var/www/social/bin/console psysh'
|
||||
|
||||
%.mo : %.po
|
||||
msgfmt -o $@ $<
|
||||
php-shell: .PHONY
|
||||
docker exec -it $(strip $(DIR))_php_1 sh -c 'cd /var/www/social; sh'
|
||||
|
||||
psql-shell: .PHONY
|
||||
docker exec -it $(strip $(DIR))_db_1 sh -c "psql -U postgres social"
|
||||
|
||||
database-force-schema-update:
|
||||
docker exec -it $(strip $(DIR))_php_1 sh -c "/var/www/social/bin/console doctrine:schema:update --dump-sql --force"
|
||||
|
||||
test: .PHONY
|
||||
cd docker/testing && docker-compose run php; docker-compose down
|
||||
|
||||
stop-test: .PHONY
|
||||
cd docker/testing && docker-compose down
|
||||
|
||||
157
README.md
157
README.md
@@ -1,157 +0,0 @@
|
||||
# GNU social 1.20.x
|
||||
(c) 2010-2019 Free Software Foundation, Inc
|
||||
|
||||
This is the README file for GNU social, the free
|
||||
software social networking platform. It includes
|
||||
general information about the software and the
|
||||
project.
|
||||
|
||||
The file INSTALL.md has useful instructions on how to
|
||||
install this software.
|
||||
|
||||
System administrators may find the `DOCUMENTATION/SYSTEM_ADMINISTRATORS`
|
||||
directory useful, namely:
|
||||
|
||||
- upgrade_from: upgrading from different software
|
||||
- CONFIGURE.md: configuration options in gruesome detail.
|
||||
- PLUGINS.md: how to install and configure plugins.
|
||||
|
||||
Developers may find the `DOCUMENTATION/DEVELOPERS` directory useful.
|
||||
|
||||
## About
|
||||
|
||||
GNU social is a free social networking
|
||||
platform. It helps people in a community, company
|
||||
or group to exchange short status updates, do
|
||||
polls, announce events, or other social activities
|
||||
(and you can add more!). Users can choose which
|
||||
people to "follow" and receive only their friends'
|
||||
or colleagues' status messages. It provides a
|
||||
similar service to proprietary social network sites,
|
||||
but is much more awesome.
|
||||
|
||||
With a little work, status messages can be sent to
|
||||
mobile phones, instant messenger programs (using
|
||||
XMPP), and specially-designed desktop clients that
|
||||
support the Twitter API.
|
||||
|
||||
GNU social supports open standards (such as OStatus
|
||||
<https://www.w3.org/community/ostatus/>) that lets users in
|
||||
different networks follow each other. It enables a
|
||||
distributed social network spread all across the
|
||||
Web.
|
||||
|
||||
GNU social was originally developed as "StatusNet" by
|
||||
StatusNet, Inc. with Evan Prodromou as lead developer.
|
||||
|
||||
It is shared with you in hope that you too make an
|
||||
service available to your users. To learn more,
|
||||
please see the Open Software Service Definition
|
||||
1.1: <http://www.opendefinition.org/ossd>
|
||||
|
||||
### License
|
||||
|
||||
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, in the file "COPYING". If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
IMPORTANT NOTE: The GNU Affero General Public License (AGPL) has
|
||||
*different requirements* from the "regular" GPL. In particular, if
|
||||
you make modifications to the GNU social source code on your server,
|
||||
you *MUST MAKE AVAILABLE* the modified version of the source code
|
||||
to your users under the same license. This is a legal requirement
|
||||
of using the software, and if you do not wish to share your
|
||||
modifications, *YOU MAY NOT INSTALL GNU SOCIAL*.
|
||||
|
||||
Documentation in the /doc-src/ directory is available under the
|
||||
Creative Commons Attribution 3.0 Unported license, with attribution to
|
||||
"GNU social". See <http://creativecommons.org/licenses/by/3.0/> for details.
|
||||
|
||||
CSS and images in the /theme/ directory are available under the
|
||||
Creative Commons Attribution 3.0 Unported license, with attribution to
|
||||
"GNU social". See <http://creativecommons.org/licenses/by/3.0/> for details.
|
||||
|
||||
Our understanding and intention is that if you add your own theme that
|
||||
uses only CSS and images, those files are not subject to the copyleft
|
||||
requirements of the Affero General Public License 3.0. See
|
||||
<http://wordpress.org/news/2009/07/themes-are-gpl-too/>. This is not
|
||||
legal advice; consult your lawyer.
|
||||
|
||||
Additional library software has been made available in the 'extlib'
|
||||
directory. All of it is Free Software and can be distributed under
|
||||
liberal terms, but those terms may differ in detail from the AGPL's
|
||||
particulars. See each package's license file in the extlib directory
|
||||
for additional terms.
|
||||
|
||||
Refer to COPYING.md for full text of the software license..
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
The primary output for GNU social is syslog,
|
||||
unless you configured a separate logfile. This is
|
||||
probably the first place to look if you're getting
|
||||
weird behaviour from GNU social.
|
||||
|
||||
If you're tracking the unstable version of
|
||||
GNU social in the git repository (see below), and you
|
||||
get a compilation error ("unexpected T_STRING") in
|
||||
the browser, check to see that you don't have any
|
||||
conflicts in your code.
|
||||
|
||||
### Unstable version
|
||||
|
||||
If you're adventurous or impatient, you may want
|
||||
to install the development version of GNU social.
|
||||
To get it, use the git version control tool
|
||||
<http://git-scm.com/> like so:
|
||||
|
||||
git clone git@notabug.org:diogo/gnu-social.git
|
||||
|
||||
In the current phase of development it is probably
|
||||
recommended to use git as a means to stay up to date
|
||||
with the source code. You can choose between these
|
||||
branches:
|
||||
* 1.20.x "oldstable", few updates, well tested coded
|
||||
* master "stable", usually working well
|
||||
* nightly "testing", most updates, not always working as expected
|
||||
|
||||
To keep it up-to-date, use `git pull`. Watch for conflicts!
|
||||
|
||||
As in any upgrade, do __not__ forget to run `/scripts/upgrade.php`.
|
||||
|
||||
## Further information
|
||||
|
||||
There are several ways to get more information about GNU social.
|
||||
|
||||
* The #social IRC channel on freenode.net <https://www.freenode.net/>.
|
||||
* The unofficial XMPP room linked to IRC on <xmpp:gnusocial@conference.bka.li>
|
||||
* The GNU social website <https://gnu.io/social/>
|
||||
|
||||
* GNU social has a bug tracker for any defects you may find, or ideas for
|
||||
making things better. <https://notabug.org/diogo/gnu-social/issues>
|
||||
* Patches are welcome, preferrably to our repository on notabug.org. <https://notabug.org/diogo/gnu-social>
|
||||
|
||||
## Credits
|
||||
|
||||
An incomplete list of developers who've worked on GNU social,
|
||||
or its predecessors StatusNet and Free Social has been made available
|
||||
in `CREDITS.md`.
|
||||
|
||||
### Current team
|
||||
|
||||
* Matt Lee
|
||||
* Mikael Nordfeldth
|
||||
* Diogo Cordeiro
|
||||
* Bruno Casteleiro
|
||||
* Miguel Dantas
|
||||
* Alexei Sorokin
|
||||
@@ -1,214 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Site access administration panel
|
||||
*
|
||||
* 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 Settings
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Administer site access settings
|
||||
*
|
||||
* @category Admin
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AccessadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
/**
|
||||
* Returns the page title
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
function title()
|
||||
{
|
||||
// TRANS: Page title for Access admin panel that allows configuring site access.
|
||||
return _('Access');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for using this form.
|
||||
*
|
||||
* @return string instructions
|
||||
*/
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Page notice.
|
||||
return _('Site access settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the site admin panel form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showForm()
|
||||
{
|
||||
$form = new AccessAdminPanelForm($this);
|
||||
$form->show();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings from the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function saveSettings()
|
||||
{
|
||||
static $booleans = array('site' => array('private', 'inviteonly', 'closed'),
|
||||
'public' => array('localonly'));
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
$values[$section][$setting] = ($this->boolean($setting)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
$config = new Config();
|
||||
|
||||
$config->query('BEGIN');
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
Config::save($section, $setting, $values[$section][$setting]);
|
||||
}
|
||||
}
|
||||
|
||||
$config->query('COMMIT');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class AccessAdminPanelForm extends AdminForm
|
||||
{
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return int ID of the form
|
||||
*/
|
||||
function id()
|
||||
{
|
||||
return 'form_site_admin_panel';
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string class of the form
|
||||
*/
|
||||
function formClass()
|
||||
{
|
||||
return 'form_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
function action()
|
||||
{
|
||||
return common_local_url('accessadminpanel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_account_access'));
|
||||
// TRANS: Form legend for registration form.
|
||||
$this->out->element('legend', null, _('Registration'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->li();
|
||||
// TRANS: Checkbox instructions for admin setting "Invite only".
|
||||
$instructions = _('Make registration invitation only.');
|
||||
// TRANS: Checkbox label for configuring site as invite only.
|
||||
$this->out->checkbox('inviteonly', _('Invite only'),
|
||||
(bool) $this->value('inviteonly'),
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Checkbox instructions for admin setting "Closed" (no new registrations).
|
||||
$instructions = _('Disable new registrations.');
|
||||
// TRANS: Checkbox label for disabling new user registrations.
|
||||
$this->out->checkbox('closed', _('Closed'),
|
||||
(bool) $this->value('closed'),
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
|
||||
|
||||
// Public access settings (login requirements for feeds etc.)
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_public_access'));
|
||||
// TRANS: Form legend for registration form.
|
||||
$this->out->element('legend', null, _('Feed access'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
// TRANS: Checkbox instructions for admin setting "Private".
|
||||
$instructions = _('Prohibit anonymous users (not logged in) from viewing site?');
|
||||
// TRANS: Checkbox label for prohibiting anonymous users from viewing site.
|
||||
$this->out->checkbox('private', _m('LABEL', 'Private'),
|
||||
(bool) $this->value('private'),
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Description of the full network notice stream views..
|
||||
$instructions = _('The full network view includes (public) remote notices which may be unrelated to local conversations.');
|
||||
// TRANS: Checkbox label for hiding remote network posts if they have not been interacted with locally.
|
||||
$this->out->checkbox('localonly', _('Restrict full network view to accounts'),
|
||||
(bool) $this->value('localonly', 'public'),
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function formActions()
|
||||
{
|
||||
// TRANS: Button title to save access settings in site admin panel.
|
||||
$title = _('Save access settings.');
|
||||
// TRANS: Button text to save access settings in site admin panel.
|
||||
$this->out->submit('submit', _m('BUTTON', 'Save'), 'submit', null, $title);
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008-2010, StatusNet, Inc.
|
||||
*
|
||||
* Action to add a people tag to a user.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/togglepeopletag.php';
|
||||
|
||||
/**
|
||||
*
|
||||
* Action to tag a profile with a single tag.
|
||||
*
|
||||
* Takes parameters:
|
||||
*
|
||||
* - tagged: the ID of the profile being tagged
|
||||
* - token: session token to prevent CSRF attacks
|
||||
* - ajax: boolean; whether to return Ajax or full-browser results
|
||||
* - peopletag_id: the ID of the tag being used
|
||||
*
|
||||
* Only works if the current user is logged in.
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AddpeopletagAction extends Action
|
||||
{
|
||||
var $user;
|
||||
var $tagged;
|
||||
var $peopletag;
|
||||
|
||||
/**
|
||||
* Check pre-requisites and instantiate attributes
|
||||
*
|
||||
* @param Array $args array of arguments (URL, GET, POST)
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// CSRF protection
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
// TRANS: Client error displayed when the session token does not match or is not given.
|
||||
$this->clientError(_('There was a problem with your session token.'.
|
||||
' Try again, please.'));
|
||||
}
|
||||
|
||||
// Only for logged-in users
|
||||
|
||||
$this->user = common_current_user();
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Error message displayed when trying to perform an action that requires a logged in user.
|
||||
$this->clientError(_('Not logged in.'));
|
||||
}
|
||||
|
||||
// Profile to subscribe to
|
||||
|
||||
$tagged_id = $this->arg('tagged');
|
||||
|
||||
$this->tagged = Profile::getKV('id', $tagged_id);
|
||||
|
||||
if (empty($this->tagged)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing profile.
|
||||
$this->clientError(_('No such profile.'));
|
||||
}
|
||||
|
||||
$id = $this->arg('peopletag_id');
|
||||
$this->peopletag = Profile_list::getKV('id', $id);
|
||||
|
||||
if (empty($this->peopletag)) {
|
||||
// TRANS: Client error displayed trying to reference a non-existing list.
|
||||
$this->clientError(_('No such list.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request
|
||||
*
|
||||
* Does the tagging and returns results.
|
||||
*
|
||||
* @param Array $args unused.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
// Throws exception on error
|
||||
$ptag = Profile_tag::setTag($this->user->id, $this->tagged->id,
|
||||
$this->peopletag->tag);
|
||||
|
||||
if (!$ptag) {
|
||||
$user = User::getKV('id', $id);
|
||||
if ($user) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when an unknown error occurs when adding a user to a list.
|
||||
// TRANS: %s is a username.
|
||||
sprintf(_('There was an unexpected error while listing %s.'),
|
||||
$user->nickname));
|
||||
} else {
|
||||
// TRANS: Client error displayed when an unknown error occurs when adding a user to a list.
|
||||
// TRANS: %s is a profile URL.
|
||||
$this->clientError(sprintf(_('There was a problem listing %s. ' .
|
||||
'The remote server is probably not responding correctly. ' .
|
||||
'Please try retrying later.'), $this->profile->profileurl));
|
||||
}
|
||||
}
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title after adding a user to a list.
|
||||
$this->element('title', null, _m('TITLE','Listed'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$unsubscribe = new UntagButton($this, $this->tagged, $this->peopletag);
|
||||
$unsubscribe->show();
|
||||
$this->elementEnd('body');
|
||||
$this->endHTML();
|
||||
} else {
|
||||
$url = common_local_url('subscriptions',
|
||||
array('nickname' => $this->user->nickname));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
}
|
||||
}
|
||||
182
actions/all.php
182
actions/all.php
@@ -1,182 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008-2011, 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/>.
|
||||
*
|
||||
* @category Actions
|
||||
* @package Actions
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @author Brenda Wallace <shiny@cpan.org>
|
||||
* @author Brion Vibber <brion@pobox.com>
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Meitar Moscovitz <meitarm@gmail.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <millette@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license GNU Affero General Public License http://www.gnu.org/licenses/
|
||||
* @link http://status.net
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class AllAction extends ShowstreamAction
|
||||
{
|
||||
public function getStream()
|
||||
{
|
||||
if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
|
||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||
} else {
|
||||
$stream = new ThreadingInboxNoticeStream($this->target, $this->scoped);
|
||||
}
|
||||
|
||||
return $stream;
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
if (!empty($this->scoped) && $this->scoped->sameAs($this->target)) {
|
||||
// TRANS: Title of a user's own start page.
|
||||
return _('Home timeline');
|
||||
} else {
|
||||
// TRANS: Title of another user's start page.
|
||||
// TRANS: %s is the other user's name.
|
||||
return sprintf(_("%s's home timeline"), $this->target->getBestName());
|
||||
}
|
||||
}
|
||||
|
||||
function getFeeds()
|
||||
{
|
||||
return array(
|
||||
new Feed(Feed::JSON,
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'as',
|
||||
'id' => $this->target->getNickname()
|
||||
)
|
||||
),
|
||||
// TRANS: %s is user nickname.
|
||||
sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->getNickname())),
|
||||
new Feed(Feed::RSS1,
|
||||
common_local_url(
|
||||
'allrss', array(
|
||||
'nickname' =>
|
||||
$this->target->getNickname())
|
||||
),
|
||||
// TRANS: %s is user nickname.
|
||||
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->target->getNickname())),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'rss',
|
||||
'id' => $this->target->getNickname()
|
||||
)
|
||||
),
|
||||
// TRANS: %s is user nickname.
|
||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->getNickname())),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'atom',
|
||||
'id' => $this->target->getNickname()
|
||||
)
|
||||
),
|
||||
// TRANS: %s is user nickname.
|
||||
sprintf(_('Feed for friends of %s (Atom)'), $this->target->getNickname()))
|
||||
);
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
// TRANS: Empty list message. %s is a user nickname.
|
||||
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->target->getNickname()) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
if ($this->target->id === $this->scoped->id) {
|
||||
// TRANS: Encouragement displayed on logged in user's empty timeline.
|
||||
// TRANS: This message contains Markdown links. Keep "](" together.
|
||||
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
|
||||
} else {
|
||||
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@".
|
||||
// TRANS: This message contains Markdown links. Keep "](" together.
|
||||
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->target->getNickname(), $this->target->getNickname(), '@' . $this->target->getNickname());
|
||||
}
|
||||
} else {
|
||||
// TRANS: Encouragement displayed on empty timeline user pages for anonymous users.
|
||||
// TRANS: %s is a user nickname. This message contains Markdown links. Keep "](" together.
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->target->getNickname());
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
if (Event::handle('StartShowAllContent', array($this))) {
|
||||
if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
|
||||
$nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
|
||||
} else {
|
||||
$nl = new ThreadedNoticeList($this->notice, $this, $this->scoped);
|
||||
}
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$this->pagination(
|
||||
$this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'all', array('nickname' => $this->target->getNickname())
|
||||
);
|
||||
|
||||
Event::handle('EndShowAllContent', array($this));
|
||||
}
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
// Show invite button, as long as site isn't closed, and
|
||||
// we have a logged in user.
|
||||
if (common_config('invite', 'enabled') && !common_config('site', 'closed') && common_logged_in()) {
|
||||
if (!common_config('site', 'private')) {
|
||||
$ibs = new InviteButtonSection(
|
||||
$this,
|
||||
// TRANS: Button text for inviting more users to the StatusNet instance.
|
||||
// TRANS: Less business/enterprise-oriented language for public sites.
|
||||
_m('BUTTON', 'Send invite')
|
||||
);
|
||||
} else {
|
||||
$ibs = new InviteButtonSection($this);
|
||||
}
|
||||
$ibs->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadingInboxNoticeStream extends ThreadingNoticeStream
|
||||
{
|
||||
function __construct(Profile $target, Profile $scoped=null)
|
||||
{
|
||||
parent::__construct(new InboxNoticeStream($target, $scoped));
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* RSS feed for user and friends timeline action class.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <millette@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, 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/>.
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* RSS feed for user and friends timeline.
|
||||
*
|
||||
* Formatting of RSS handled by Rss10Action
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <millette@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AllrssAction extends TargetedRss10Action
|
||||
{
|
||||
protected function getNotices()
|
||||
{
|
||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||
return $stream->getNotices(0, $this->limit)->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get channel.
|
||||
*
|
||||
* @return array associative array on channel information
|
||||
*/
|
||||
function getChannel()
|
||||
{
|
||||
$c = array('url' => common_local_url('allrss',
|
||||
array('nickname' =>
|
||||
$this->target->getNickname())),
|
||||
// TRANS: Message is used as link title. %s is a user nickname.
|
||||
'title' => sprintf(_('%s and friends'), $this->target->getNickname()),
|
||||
'link' => common_local_url('all',
|
||||
array('nickname' =>
|
||||
$this->target->getNickname())),
|
||||
// TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
|
||||
'description' => sprintf(_('Updates from %1$s and friends on %2$s!'),
|
||||
$this->target->getNickname(), common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Dummy action that emulates Twitter's rate limit status API resource
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Brion Vibber <brion@pobox.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* We don't have a rate limit, but some clients check this method.
|
||||
* It always returns the same thing: 150 hits left.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
public function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Return some Twitter-ish data about API limits
|
||||
*
|
||||
* @return void
|
||||
* @throws ClientException
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, ['xml', 'json'])) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
|
||||
$reset = new DateTime();
|
||||
$reset->modify('+1 hour');
|
||||
|
||||
$this->initDocument($this->format);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->elementStart('hash');
|
||||
$this->element('remaining-hits', ['type' => 'integer'], "150");
|
||||
$this->element('hourly-limit', ['type' => 'integer'], "150");
|
||||
$this->element(
|
||||
'reset-time',
|
||||
['type' => 'datetime'],
|
||||
common_date_iso8601($reset->format('r'))
|
||||
);
|
||||
$this->element(
|
||||
'reset_time_in_seconds',
|
||||
['type' => 'integer'],
|
||||
strtotime('+1 hour')
|
||||
);
|
||||
$this->elementEnd('hash');
|
||||
} elseif ($this->format == 'json') {
|
||||
$out = [
|
||||
'reset_time_in_seconds' => strtotime('+1 hour'),
|
||||
'remaining_hits' => 150,
|
||||
'hourly_limit' => 150,
|
||||
'reset_time' => common_date_rfc2822(
|
||||
$reset->format('r')
|
||||
)
|
||||
];
|
||||
print json_encode($out);
|
||||
}
|
||||
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Register account
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiAccountRegisterAction extends ApiAction
|
||||
{
|
||||
|
||||
/**
|
||||
* Has there been an error?
|
||||
*/
|
||||
var $error = null;
|
||||
|
||||
/**
|
||||
* Have we registered?
|
||||
*/
|
||||
var $registered = false;
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
protected $code = null; // invite code
|
||||
protected $invite = null; // invite to-be-stored
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$this->code = $this->trimmed('code');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$email = $this->trimmed('email');
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$bio = $this->trimmed('bio');
|
||||
$location = $this->trimmed('location');
|
||||
|
||||
// We don't trim these... whitespace is OK in a password!
|
||||
$password = $this->arg('password');
|
||||
$confirm = $this->arg('confirm');
|
||||
|
||||
if (empty($this->code)) {
|
||||
common_ensure_session();
|
||||
if (array_key_exists('invitecode', $_SESSION)) {
|
||||
$this->code = $_SESSION['invitecode'];
|
||||
}
|
||||
}
|
||||
|
||||
if (common_config('site', 'inviteonly') && empty($this->code)) {
|
||||
// TRANS: Client error displayed when trying to register to an invite-only site without an invitation.
|
||||
$this->clientError(_('Sorry, only invited people can register.'), 401);
|
||||
}
|
||||
|
||||
if (!empty($this->code)) {
|
||||
$this->invite = Invitation::getKV('code', $this->code);
|
||||
if (empty($this->invite)) {
|
||||
// TRANS: Client error displayed when trying to register to an invite-only site without a valid invitation.
|
||||
$this->clientError(_('Sorry, invalid invitation code.'), 401);
|
||||
}
|
||||
// Store this in case we need it
|
||||
common_ensure_session();
|
||||
$_SESSION['invitecode'] = $this->code;
|
||||
}
|
||||
|
||||
// Input scrubbing
|
||||
try {
|
||||
$nickname = Nickname::normalize($nickname, true);
|
||||
} catch (NicknameException $e) {
|
||||
// clientError handles Api exceptions with various formats and stuff
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
$email = common_canonical_email($email);
|
||||
|
||||
if ($email && !Validate::email($email, common_config('email', 'check_domain'))) {
|
||||
// TRANS: Form validation error displayed when trying to register without a valid e-mail address.
|
||||
$this->clientError(_('Not a valid email address.'), 400);
|
||||
} else if ($this->emailExists($email)) {
|
||||
// TRANS: Form validation error displayed when trying to register with an already registered e-mail address.
|
||||
$this->clientError(_('Email address already exists.'), 400);
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!common_valid_http_url($homepage)) {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid homepage URL.
|
||||
$this->clientError(_('Homepage is not a valid URL.'), 400);
|
||||
} else if (Profile::bioTooLong($bio)) {
|
||||
// TRANS: Form validation error on registration page when providing too long a bio text.
|
||||
// TRANS: %d is the maximum number of characters for bio; used for plural.
|
||||
$this->clientError(sprintf(_m('Bio is too long (maximum %d character).',
|
||||
'Bio is too long (maximum %d characters).',
|
||||
Profile::maxBio()),
|
||||
Profile::maxBio()), 400);
|
||||
} else if (strlen($password) < 6) {
|
||||
// TRANS: Form validation error displayed when trying to register with too short a password.
|
||||
$this->clientError(_('Password must be 6 or more characters.'), 400);
|
||||
} else if ($password != $confirm) {
|
||||
// TRANS: Form validation error displayed when trying to register with non-matching passwords.
|
||||
$this->clientError(_('Passwords do not match.'), 400);
|
||||
} else {
|
||||
|
||||
// annoy spammers
|
||||
sleep(7);
|
||||
|
||||
if (Event::handle('APIStartRegistrationTry', array($this))) {
|
||||
try {
|
||||
$user = User::register(array('nickname' => $nickname,
|
||||
'password' => $password,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'bio' => $bio,
|
||||
'location' => $location,
|
||||
'code' => $this->code));
|
||||
Event::handle('EndRegistrationTry', array($this));
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->twitterUserArray($user->getProfile()));
|
||||
$this->endDocument('json');
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the given email address already exist?
|
||||
*
|
||||
* Checks a canonical email address against the database.
|
||||
*
|
||||
* @param string $email email address to check
|
||||
*
|
||||
* @return boolean true if the address already exists
|
||||
*/
|
||||
function emailExists($email)
|
||||
{
|
||||
$email = common_canonical_email($email);
|
||||
if (!$email || strlen($email) == 0) {
|
||||
return false;
|
||||
}
|
||||
$user = User::getKV('email', $email);
|
||||
return is_object($user);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update a user's background color
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiAccountUpdateBackgroundColorAction extends ApiAuthAction
|
||||
{
|
||||
var $backgroundcolor = null;
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$this->backgroundcolor = $this->trimmed('backgroundcolor');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Try to save the user's colors in her design. Create a new design
|
||||
* if the user doesn't already have one.
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$validhex = preg_match('/^[a-f0-9]{6}$/i',$this->backgroundcolor);
|
||||
if ($validhex === false || $validhex == 0) {
|
||||
$this->clientError(_('Not a valid hex color.'), 400);
|
||||
}
|
||||
|
||||
// save the new color
|
||||
$original = clone($this->auth_user);
|
||||
$this->auth_user->backgroundcolor = $this->backgroundcolor;
|
||||
if (!$this->auth_user->update($original)) {
|
||||
$this->clientError(_('Error updating user.'), 404);
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->scoped, true);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update the authenticating user notification channels
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets which channel (device) StatusNet delivers updates to for
|
||||
* the authenticating user. Sending none as the device parameter
|
||||
* will disable IM and/or SMS updates.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->device = $this->trimmed('device');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* See which request params have been set, and update the user settings
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
|
||||
// Note: Twitter no longer supports IM
|
||||
|
||||
if (!in_array(strtolower($this->device), array('sms', 'im', 'none'))) {
|
||||
// TRANS: Client error displayed when no valid device parameter is provided for a user's delivery device setting.
|
||||
$this->clientError(_( 'You must specify a parameter named ' .
|
||||
'\'device\' with a value of one of: sms, im, none.' ));
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed when no existing user is provided for a user's delivery device setting.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$original = clone($this->user);
|
||||
|
||||
if (strtolower($this->device) == 'sms') {
|
||||
$this->user->smsnotify = true;
|
||||
} elseif (strtolower($this->device) == 'im') {
|
||||
//TODO IM is pluginized now, so what should we do?
|
||||
//Enable notifications for all IM plugins?
|
||||
//For now, don't do anything
|
||||
//$this->user->jabbernotify = true;
|
||||
} elseif (strtolower($this->device == 'none')) {
|
||||
$this->user->smsnotify = false;
|
||||
//TODO IM is pluginized now, so what should we do?
|
||||
//Disable notifications for all IM plugins?
|
||||
//For now, don't do anything
|
||||
//$this->user->jabbernotify = false;
|
||||
}
|
||||
|
||||
$result = $this->user->update($original);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($this->user, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error displayed when a user's delivery device cannot be updated.
|
||||
$this->serverError(_('Could not update user.'));
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
$twitter_user = $this->twitterUserArray($profile, true);
|
||||
|
||||
// Note: this Twitter API method is retarded because it doesn't give
|
||||
// any success/failure information. Twitter's docs claim that the
|
||||
// notification field will change to reflect notification choice,
|
||||
// but that's not true; notification> is used to indicate
|
||||
// whether the auth user is following the user in question.
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update a user's link color
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiAccountUpdateLinkColorAction extends ApiAuthAction
|
||||
{
|
||||
var $linkcolor = null;
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$this->linkcolor = $this->trimmed('linkcolor');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Try to save the user's colors in her design. Create a new design
|
||||
* if the user doesn't already have one.
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$validhex = preg_match('/^[a-f0-9]{6}$/i',$this->linkcolor);
|
||||
if ($validhex === false || $validhex == 0) {
|
||||
$this->clientError(_('Not a valid hex color.'), 400);
|
||||
}
|
||||
|
||||
// save the new color
|
||||
$original = clone($this->auth_user);
|
||||
$this->auth_user->linkcolor = $this->linkcolor;
|
||||
if (!$this->auth_user->update($original)) {
|
||||
$this->clientError(_('Error updating user.'), 400);
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->scoped, true);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update the authenticating user's 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 API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* API analog to the profile settings page
|
||||
* Only the parameters specified will be updated.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountUpdateProfileAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
$this->name = $this->trimmed('name');
|
||||
$this->url = $this->trimmed('url');
|
||||
$this->location = $this->trimmed('location');
|
||||
$this->description = $this->trimmed('description');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* See which request params have been set, and update the profile
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed if a user could not be found.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if (empty($profile)) {
|
||||
// TRANS: Error message displayed when referring to a user without a profile.
|
||||
$this->clientError(_('User has no profile.'));
|
||||
}
|
||||
|
||||
$original = clone($profile);
|
||||
|
||||
$profile->fullname = $this->name;
|
||||
$profile->homepage = $this->url;
|
||||
$profile->bio = $this->description;
|
||||
$profile->location = $this->location;
|
||||
|
||||
if (!empty($this->location)) {
|
||||
$loc = Location::fromName($this->location);
|
||||
|
||||
if (!empty($loc)) {
|
||||
$profile->lat = $loc->lat;
|
||||
$profile->lon = $loc->lon;
|
||||
$profile->location_id = $loc->location_id;
|
||||
$profile->location_ns = $loc->location_ns;
|
||||
}
|
||||
} else {
|
||||
// location is empty so reset the extrapolated information too
|
||||
$profile->lat = '';
|
||||
$profile->lon = '';
|
||||
$profile->location_id = '';
|
||||
$profile->location_ns = '';
|
||||
}
|
||||
|
||||
$result = $profile->update($original);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($profile, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error displayed if a user profile could not be saved.
|
||||
$this->serverError(_('Could not save profile.'));
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($profile, true);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update the authenticating user's profile image
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the authenticating user's profile image. Note that this API method
|
||||
* expects raw multipart data, not a URL to an image.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountUpdateProfileImageAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check whether the credentials are valid and output the result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed updating profile image without having a user object.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
try {
|
||||
$imagefile = ImageFile::fromUpload('image');
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage());
|
||||
}
|
||||
|
||||
$type = $imagefile->preferredType();
|
||||
$filename = Avatar::filename(
|
||||
$user->id,
|
||||
image_type_to_extension($type),
|
||||
null,
|
||||
'tmp'.common_timestamp()
|
||||
);
|
||||
|
||||
$filepath = Avatar::path($filename);
|
||||
|
||||
$imagefile->copyTo($filepath);
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$profile->setOriginal($filename);
|
||||
|
||||
$twitter_user = $this->twitterUserArray($profile, true);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Test if supplied user credentials are valid.
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a user's credentials. Returns an HTTP 200 OK response code and a
|
||||
* representation of the requesting user if authentication was successful;
|
||||
* returns a 401 status code and an error message if not.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountVerifyCredentialsAction extends ApiAuthAction
|
||||
{
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->auth_user->getProfile(), true);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* An AtomPub service document for a user
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an AtomPub service document for a user
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAtomServiceAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->user = $this->getTargetUser($this->arg('id'));
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed when making an Atom API request for an unknown user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the arguments. In our case, show a service document.
|
||||
*
|
||||
* @param Array $args unused.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
header('Content-Type: application/atomsvc+xml');
|
||||
|
||||
$this->startXML();
|
||||
$this->elementStart('service', array('xmlns' => 'http://www.w3.org/2007/app',
|
||||
'xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
||||
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/'));
|
||||
$this->elementStart('workspace');
|
||||
// TRANS: Title for Atom feed.
|
||||
$this->element('atom:title', null, _m('ATOM','Main'));
|
||||
$this->elementStart('collection',
|
||||
array('href' => common_local_url('ApiTimelineUser',
|
||||
array('id' => $this->user->id,
|
||||
'format' => 'atom'))));
|
||||
$this->element('atom:title',
|
||||
null,
|
||||
// TRANS: Title for Atom feed. %s is a user nickname.
|
||||
sprintf(_("%s timeline"),
|
||||
$this->user->nickname));
|
||||
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||
$this->element('activity:verb', null, ActivityVerb::POST);
|
||||
$this->elementEnd('collection');
|
||||
$this->elementStart('collection',
|
||||
array('href' => common_local_url('AtomPubSubscriptionFeed',
|
||||
array('subscriber' => $this->user->id))));
|
||||
$this->element('atom:title',
|
||||
null,
|
||||
// TRANS: Title for Atom feed with a user's subscriptions. %s is a user nickname.
|
||||
sprintf(_("%s subscriptions"),
|
||||
$this->user->nickname));
|
||||
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||
$this->element('activity:verb', null, ActivityVerb::FOLLOW);
|
||||
$this->elementEnd('collection');
|
||||
$this->elementStart('collection',
|
||||
array('href' => common_local_url('AtomPubFavoriteFeed',
|
||||
array('profile' => $this->user->id))));
|
||||
$this->element('atom:title',
|
||||
null,
|
||||
// TRANS: Title for Atom feed with a user's favorite notices. %s is a user nickname.
|
||||
sprintf(_("%s favorites"),
|
||||
$this->user->nickname));
|
||||
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||
$this->element('activity:verb', null, ActivityVerb::FAVORITE);
|
||||
$this->elementEnd('collection');
|
||||
$this->elementStart('collection',
|
||||
array('href' => common_local_url('AtomPubMembershipFeed',
|
||||
array('profile' => $this->user->id))));
|
||||
$this->element('atom:title',
|
||||
null,
|
||||
// TRANS: Title for Atom feed with a user's memberships. %s is a user nickname.
|
||||
sprintf(_("%s memberships"),
|
||||
$this->user->nickname));
|
||||
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||
$this->element('activity:verb', null, ActivityVerb::JOIN);
|
||||
$this->elementEnd('collection');
|
||||
$this->elementEnd('workspace');
|
||||
$this->elementEnd('service');
|
||||
$this->endXML();
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a notice's attachment
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Show a notice's attachment
|
||||
*
|
||||
*/
|
||||
class ApiAttachmentAction extends ApiAuthAction
|
||||
{
|
||||
const MAXCOUNT = 100;
|
||||
|
||||
var $original = null;
|
||||
var $cnt = self::MAXCOUNT;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$file = new File();
|
||||
$file->selectAdd(); // clears it
|
||||
$file->selectAdd('url');
|
||||
$file->id = $this->trimmed('id');
|
||||
$url = $file->fetchAll('url');
|
||||
|
||||
$file_txt = '';
|
||||
if(strstr($url[0],'.html')) {
|
||||
$file_txt['txt'] = file_get_contents($url[0]);
|
||||
$file_txt['body_start'] = strpos($file_txt['txt'],'<body>')+6;
|
||||
$file_txt['body_end'] = strpos($file_txt['txt'],'</body>');
|
||||
$file_txt = substr($file_txt['txt'],$file_txt['body_start'],$file_txt['body_end']-$file_txt['body_start']);
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($file_txt);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Block a user via the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks the user specified in the ID parameter as the authenticating user.
|
||||
* Destroys a friendship to the blocked user if it exists. Returns the
|
||||
* blocked user in the requested format when successful.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiBlockCreateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new message
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->user) || empty($this->other)) {
|
||||
// TRANS: Client error displayed when trying to block a non-existing user or a user from another site.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
// Don't allow blocking yourself!
|
||||
|
||||
if ($this->user->id == $this->other->id) {
|
||||
// TRANS: Client error displayed when users try to block themselves.
|
||||
$this->clientError(_("You cannot block yourself!"), 403);
|
||||
}
|
||||
|
||||
if (!$this->user->hasBlocked($this->other)) {
|
||||
if (Event::handle('StartBlockProfile', array($this->user, $this->other))) {
|
||||
$result = $this->user->block($this->other);
|
||||
if ($result) {
|
||||
Event::handle('EndBlockProfile', array($this->user, $this->other));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->user->hasBlocked($this->other)) {
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
$this->endDocument($this->format);
|
||||
} else {
|
||||
// TRANS: Server error displayed when blocking a user has failed.
|
||||
$this->serverError(_('Block user failed.'), 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Un-block a user via the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-blocks the user specified in the ID parameter for the authenticating user.
|
||||
* Returns the un-blocked user in the requested format when successful.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiBlockDestroyAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->user) || empty($this->other)) {
|
||||
// TRANS: Client error when user not found for an API action to remove a block for a user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if ($this->user->hasBlocked($this->other)) {
|
||||
if (Event::handle('StartUnblockProfile', array($this->user, $this->other))) {
|
||||
$result = $this->user->unblock($this->other);
|
||||
if ($result) {
|
||||
Event::handle('EndUnblockProfile', array($this->user, $this->other));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->user->hasBlocked($this->other)) {
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
$this->endDocument($this->format);
|
||||
} else {
|
||||
// TRANS: Server error displayed when unblocking a user has failed.
|
||||
$this->serverError(_('Unblock user failed.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a notice's attachment
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Check if a url have a push-hub, i.e. if it is possible to subscribe
|
||||
*
|
||||
*/
|
||||
class ApiCheckHubAction extends ApiAuthAction
|
||||
{
|
||||
protected $url = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$this->url = urldecode($args['url']);
|
||||
|
||||
if (empty($this->url)) {
|
||||
$this->clientError(_('No URL.'), 403);
|
||||
}
|
||||
|
||||
if (!common_valid_http_url($this->url)) {
|
||||
$this->clientError(_('Invalid URL.'), 403);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$discover = new FeedDiscovery();
|
||||
|
||||
try {
|
||||
$feeduri = $discover->discoverFromURL($this->url);
|
||||
if($feeduri) {
|
||||
$huburi = $discover->getHubLink();
|
||||
}
|
||||
} catch (FeedSubNoFeedException $e) {
|
||||
$this->clientError(_('No feed found'), 403);
|
||||
} catch (FeedSubBadResponseException $e) {
|
||||
$this->clientError(_('No hub found'), 403);
|
||||
}
|
||||
|
||||
$hub_status = array();
|
||||
if ($huburi) {
|
||||
$hub_status = array('huburi' => $huburi);
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($hub_status);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check nickname
|
||||
*
|
||||
* Returns 1 if nickname is available on this instance, 0 if not. Error if site is private.
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiCheckNicknameAction extends ApiAction
|
||||
{
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (common_config('site', 'private')) {
|
||||
$this->clientError(_('This site is private.'), 403);
|
||||
}
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$nickname = $this->trimmed('nickname');
|
||||
|
||||
try {
|
||||
Nickname::normalize($nickname, true);
|
||||
$nickname_ok = 1;
|
||||
} catch (NicknameException $e) {
|
||||
$nickname_ok = 0;
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($nickname_ok);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* Show a stream of notices in a particular conversation
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a stream of notices in a particular conversation
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiconversationAction extends ApiAuthAction
|
||||
{
|
||||
protected $conversation = null;
|
||||
protected $notices = null;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$convId = $this->trimmed('id');
|
||||
|
||||
if (empty($convId)) {
|
||||
// TRANS: Client exception thrown when no conversation ID is given.
|
||||
throw new ClientException(_('No conversation ID.'));
|
||||
}
|
||||
|
||||
$this->conversation = Conversation::getKV('id', $convId);
|
||||
|
||||
if (empty($this->conversation)) {
|
||||
// TRANS: Client exception thrown when referring to a non-existing conversation ID (%d).
|
||||
throw new ClientException(sprintf(_('No conversation with ID %d.'), $convId),
|
||||
404);
|
||||
}
|
||||
|
||||
$stream = new ConversationNoticeStream($convId, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
$this->notices = $notice->fetchAll();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler method
|
||||
*
|
||||
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($argarray=null)
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Title for conversion timeline.
|
||||
$title = _m('TITLE', 'Conversation');
|
||||
$id = common_local_url('apiconversation', array('id' => $this->conversation->id, 'format' => $this->format));
|
||||
$link = common_local_url('conversation', array('id' => $this->conversation->id));
|
||||
|
||||
$self = $id;
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setUpdated('now');
|
||||
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
|
||||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last modified, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string last modified http header
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return etag, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string etag http header
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this require authentication?
|
||||
*
|
||||
* @return boolean true if delete, else false
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
|
||||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show an external user's profile information
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Ouputs information for a user, specified by ID or screen name.
|
||||
* The user's most recent status will be returned inline.
|
||||
*/
|
||||
class ApiExternalProfileShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$profileurl = urldecode($this->arg('profileurl'));
|
||||
|
||||
// TODO: Make this more ... unique!
|
||||
$this->profile = Profile::getKV('profileurl', $profileurl);
|
||||
|
||||
if (!($this->profile instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting profile information for a non-existing profile.
|
||||
$this->clientError(_('Profile not found.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->profile, true);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Subscribe to a user via the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Allows the authenticating users to follow (subscribe) the user specified in
|
||||
* the ID parameter. Returns the befriended user in the requested format when
|
||||
* successful. Returns a string describing the failure condition when unsuccessful.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiFriendshipsCreateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->other)) {
|
||||
// TRANS: Client error displayed when trying follow who's profile could not be found.
|
||||
$this->clientError(_('Could not follow user: profile not found.'), 403);
|
||||
}
|
||||
|
||||
if ($this->scoped->isSubscribed($this->other)) {
|
||||
$errmsg = sprintf(
|
||||
// TRANS: Client error displayed when trying to follow a user that's already being followed.
|
||||
// TRANS: %s is the nickname of the user that is already being followed.
|
||||
_('Could not follow user: %s is already on your list.'),
|
||||
$this->other->nickname
|
||||
);
|
||||
$this->clientError($errmsg, 403);
|
||||
}
|
||||
|
||||
try {
|
||||
Subscription::start($this->scoped, $this->other);
|
||||
} catch (AlreadyFulfilledException $e) {
|
||||
$this->clientError($e->getMessage(), 409);
|
||||
}
|
||||
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Unsubscribe to a user via API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Allows the authenticating users to unfollow (unsubscribe) the user specified in
|
||||
* the ID parameter. Returns the unfollowed user in the requested format when
|
||||
* successful. Returns a string describing the failure condition when unsuccessful.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiFriendshipsDestroyAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
protected $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->other instanceof Profile) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when trying to unfollow a user that cannot be found.
|
||||
_('Could not unfollow user: User not found.'),
|
||||
403
|
||||
);
|
||||
}
|
||||
|
||||
// Don't allow unsubscribing from yourself!
|
||||
|
||||
if ($this->scoped->id == $this->other->id) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when trying to unfollow self.
|
||||
_("You cannot unfollow yourself."),
|
||||
403
|
||||
);
|
||||
}
|
||||
|
||||
// throws an exception on error
|
||||
Subscription::cancel($this->scoped, $this->other);
|
||||
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show whether there is a friendship between two users
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Tests for the existence of friendship between two users. Will return true if
|
||||
* user_a follows user_b, otherwise will return false.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $profile_a = null;
|
||||
var $profile_b = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->profile_a = $this->getTargetProfile($this->trimmed('user_a'));
|
||||
$this->profile_b = $this->getTargetProfile($this->trimmed('user_b'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->profile_a) || empty($this->profile_b)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
|
||||
_('Two valid IDs or nick names must be supplied.'),
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
$result = Subscription::exists($this->profile_a, $this->profile_b);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->element('friends', null, $result);
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
print json_encode($result);
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show information about the relationship between two users
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Outputs detailed information about the relationship between two users
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiFriendshipsShowAction extends ApiBareAuthAction
|
||||
{
|
||||
var $source = null;
|
||||
var $target = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$source_id = (int)$this->trimmed('source_id');
|
||||
$source_screen_name = $this->trimmed('source_screen_name');
|
||||
$target_id = (int)$this->trimmed('target_id');
|
||||
$target_screen_name = $this->trimmed('target_screen_name');
|
||||
|
||||
if (!empty($source_id)) {
|
||||
$this->source = User::getKV($source_id);
|
||||
} elseif (!empty($source_screen_name)) {
|
||||
$this->source = User::getKV('nickname', $source_screen_name);
|
||||
} else {
|
||||
$this->source = $this->auth_user;
|
||||
}
|
||||
|
||||
if (!empty($target_id)) {
|
||||
$this->target = User::getKV($target_id);
|
||||
} elseif (!empty($target_screen_name)) {
|
||||
$this->target = User::getKV('nickname', $target_screen_name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this API resource requires auth. Overloaded to look
|
||||
* return true in case source_id and source_screen_name are both empty
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
if (common_config('site', 'private')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$source_id = $this->trimmed('source_id');
|
||||
$source_screen_name = $this->trimmed('source_screen_name');
|
||||
|
||||
if (empty($source_id) && empty($source_screen_name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->source)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when a source user could not be determined showing friendship.
|
||||
_('Could not determine source user.'),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->target)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when a target user could not be determined showing friendship.
|
||||
_('Could not find target user.'),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
$result = $this->twitterRelationshipArray($this->source, $this->target);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlRelationship($result[relationship]);
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
print json_encode($result);
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Dump of configuration variables
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Gives a full dump of configuration variables for this instance
|
||||
* of GNU social, minus variables that may be security-sensitive (like
|
||||
* passwords).
|
||||
* URL: https://example.com/api/gnusocial/config.(xml|json)
|
||||
* Formats: xml, json
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiGNUsocialConfigAction extends ApiAction
|
||||
{
|
||||
var $keys = array(
|
||||
'site' => array('name', 'server', 'theme', 'path', 'logo', 'fancy', 'language',
|
||||
'email', 'broughtby', 'broughtbyurl', 'timezone', 'closed',
|
||||
'inviteonly', 'private', 'textlimit', 'ssl', 'sslserver'),
|
||||
'license' => array('type', 'owner', 'url', 'title', 'image'),
|
||||
'nickname' => array('featured'),
|
||||
'profile' => array('biolimit'),
|
||||
'group' => array('desclimit'),
|
||||
'notice' => array('contentlimit'),
|
||||
'throttle' => array('enabled', 'count', 'timespan'),
|
||||
'xmpp' => array('enabled', 'server', 'port', 'user'),
|
||||
'integration' => array('source'),
|
||||
'attachments' => array('uploads', 'file_quota'),
|
||||
'url' => array('maxurllength', 'maxnoticelength'),
|
||||
);
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->elementStart('config');
|
||||
|
||||
// XXX: check that all sections and settings are legal XML elements
|
||||
|
||||
foreach ($this->keys as $section => $settings) {
|
||||
$this->elementStart($section);
|
||||
foreach ($settings as $setting) {
|
||||
$value = $this->setting($section, $setting);
|
||||
if (is_array($value)) {
|
||||
$value = implode(',', $value);
|
||||
} else if ($value === false || $value == '0') {
|
||||
$value = 'false';
|
||||
} else if ($value === true || $value == '1') {
|
||||
$value = 'true';
|
||||
}
|
||||
|
||||
// return theme logo if there's no site specific one
|
||||
if (empty($value)) {
|
||||
if ($section == 'site' && $setting == 'logo') {
|
||||
$value = Theme::path('logo.png');
|
||||
}
|
||||
}
|
||||
|
||||
$this->element($setting, null, $value);
|
||||
}
|
||||
$this->elementEnd($section);
|
||||
}
|
||||
$this->elementEnd('config');
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$result = array();
|
||||
foreach ($this->keys as $section => $settings) {
|
||||
$result[$section] = array();
|
||||
foreach ($settings as $setting) {
|
||||
$result[$section][$setting]
|
||||
= $this->setting($section, $setting);
|
||||
}
|
||||
}
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($result);
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
function setting($section, $key) {
|
||||
$result = common_config($section, $key);
|
||||
if ($key == 'file_quota') {
|
||||
// hack: adjust for the live upload limit
|
||||
if (common_config($section, 'uploads')) {
|
||||
$max = ImageFile::maxFileSizeInt();
|
||||
} else {
|
||||
$max = 0;
|
||||
}
|
||||
return min($result, $max);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* A version stamp for the API
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Returns a version number for this version of GNU social, which
|
||||
* should make things a bit easier for upgrades.
|
||||
* URL: http://identi.ca/api/statusnet/version.(xml|json)
|
||||
* Formats: xml, js
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiGNUsocialVersionAction extends ApiPrivateAuthAction
|
||||
{
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->element('version', null, GNUSOCIAL_VERSION);
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
print '"'.GNUSOCIAL_VERSION.'"';
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List a group's admins
|
||||
*
|
||||
* 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 API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* List 20 newest admins of the group specified by name or ID.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiGroupAdminsAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed trying to show group membership on a non-existing group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the admin of the group
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// XXX: RSS and Atom
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUsers($this->profiles);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonUsers($this->profiles);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the admins of a group
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
function getProfiles()
|
||||
{
|
||||
$profiles = array();
|
||||
|
||||
$profile = $this->group->getAdmins(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$profiles[] = clone($profile);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this list of profiles last modified?
|
||||
*
|
||||
* @return string datestamp of the lastest profile in the group
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language
|
||||
* the group id, and timestamps of the first and last
|
||||
* user who has joined the group
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Create a group via the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new group. Sets the authenticated user as the administrator of the group.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupCreateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $group = null;
|
||||
var $nickname = null;
|
||||
var $fullname = null;
|
||||
var $homepage = null;
|
||||
var $description = null;
|
||||
var $location = null;
|
||||
var $aliasstring = null;
|
||||
var $aliases = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->nickname = Nickname::normalize($this->arg('nickname'), true);
|
||||
$this->fullname = $this->arg('full_name');
|
||||
$this->homepage = $this->arg('homepage');
|
||||
$this->description = $this->arg('description');
|
||||
$this->location = $this->arg('location');
|
||||
$this->aliasstring = $this->arg('aliases');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new group
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error given when a user was not found (404).
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if ($this->validateParams() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$group = User_group::register(array('nickname' => $this->nickname,
|
||||
'fullname' => $this->fullname,
|
||||
'homepage' => $this->homepage,
|
||||
'description' => $this->description,
|
||||
'location' => $this->location,
|
||||
'aliases' => $this->aliases,
|
||||
'userid' => $this->user->id,
|
||||
'local' => true));
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate params for the new group
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function validateParams()
|
||||
{
|
||||
if (!is_null($this->homepage)
|
||||
&& strlen($this->homepage) > 0
|
||||
&& !common_valid_http_url($this->homepage)) {
|
||||
// TRANS: Client error in form for group creation.
|
||||
$this->clientError(_('Homepage is not a valid URL.'), 403);
|
||||
|
||||
} elseif (!is_null($this->fullname)
|
||||
&& mb_strlen($this->fullname) > 255) {
|
||||
// TRANS: Client error in form for group creation.
|
||||
$this->clientError(_('Full name is too long (maximum 255 characters).'), 403);
|
||||
|
||||
} elseif (User_group::descriptionTooLong($this->description)) {
|
||||
// TRANS: Client error shown when providing too long a description during group creation.
|
||||
// TRANS: %d is the maximum number of allowed characters.
|
||||
$this->clientError(sprintf(_m('Description is too long (maximum %d character).',
|
||||
'Description is too long (maximum %d characters).',
|
||||
User_group::maxDescription()), User_group::maxDescription()), 403);
|
||||
|
||||
} elseif (!is_null($this->location)
|
||||
&& mb_strlen($this->location) > 255) {
|
||||
// TRANS: Client error shown when providing too long a location during group creation.
|
||||
$this->clientError(_('Location is too long (maximum 255 characters).'), 403);
|
||||
}
|
||||
|
||||
if (!empty($this->aliasstring)) {
|
||||
$this->aliases = array_map(
|
||||
array('Nickname', 'normalize'), // static call to Nickname::normalize
|
||||
array_unique(preg_split('/[\s,]+/', $this->aliasstring))
|
||||
);
|
||||
} else {
|
||||
$this->aliases = array();
|
||||
}
|
||||
|
||||
if (count($this->aliases) > common_config('group', 'maxaliases')) {
|
||||
$this->clientError(sprintf(
|
||||
// TRANS: Client error shown when providing too many aliases during group creation.
|
||||
// TRANS: %d is the maximum number of allowed aliases.
|
||||
_m('Too many aliases! Maximum %d allowed.',
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')),
|
||||
403);
|
||||
}
|
||||
|
||||
// Everything looks OK
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check to see whether a user a member of a group
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a user is a member of a specified group.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupIsMemberAction extends ApiBareAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile(null);
|
||||
$this->group = $this->getTargetGroup(null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->target)) {
|
||||
// TRANS: Client error displayed when checking group membership for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed when checking group membership for a non-existing group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$is_member = $this->target->isMember($this->group);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->element('is_member', null, $is_member);
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects(array('is_member' => $is_member));
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Join a group via the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the authenticated user to the group speicified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupJoinAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Join the authenticated user to the group
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->scoped)) {
|
||||
// TRANS: Client error displayed when trying to have a non-existing user join a group.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed when trying to join a group that does not exist.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
if ($this->scoped->isMember($this->group)) {
|
||||
// TRANS: Server error displayed when trying to join a group the user is already a member of.
|
||||
$this->clientError(_('You are already a member of that group.'), 403);
|
||||
}
|
||||
|
||||
if (Group_block::isBlocked($this->group, $this->scoped)) {
|
||||
// TRANS: Server error displayed when trying to join a group the user is blocked from joining.
|
||||
$this->clientError(_('You have been blocked from that group by the admin.'), 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->scoped->joinGroup($this->group);
|
||||
} catch (Exception $e) {
|
||||
// TRANS: Server error displayed when joining a group failed in the database.
|
||||
// TRANS: %1$s is the joining user's nickname, $2$s is the group nickname for which the join failed.
|
||||
$this->serverError(sprintf(_('Could not join user %1$s to group %2$s.'),
|
||||
$this->scoped->nickname, $this->group->nickname));
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Leave a group via the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the authenticated user from the group specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupLeaveAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!$this->scoped instanceof Profile) {
|
||||
// TRANS: Client error displayed when trying to have a non-existing user leave a group.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (!$this->group instanceof User_group) {
|
||||
// TRANS: Client error displayed when trying to leave a group that does not exist.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $this->group->id;
|
||||
$member->profile_id = $this->scoped->id;
|
||||
|
||||
if (!$member->find(true)) {
|
||||
// TRANS: Server error displayed when trying to leave a group the user is not a member of.
|
||||
$this->serverError(_('You are not a member of this group.'));
|
||||
}
|
||||
|
||||
try {
|
||||
$this->user->leaveGroup($this->group);
|
||||
} catch (Exception $e) {
|
||||
// TRANS: Server error displayed when leaving a group failed in the database.
|
||||
// TRANS: %1$s is the leaving user's nickname, $2$s is the group nickname for which the leave failed.
|
||||
$this->serverError(sprintf(_('Could not remove user %1$s from group %2$s.'),
|
||||
$this->scoped->getNickname(), $this->group->nickname));
|
||||
}
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check to see whether a user a member of a group
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a user is a member of a specified group.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupListAction extends ApiBareAuthAction
|
||||
{
|
||||
var $groups = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
//TODO: Make sure this doesn't leak unwantedly for federated users
|
||||
$this->target = $this->getTargetProfile(null);
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when user not found for an action.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->groups = $this->getGroups();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the user's groups
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Used as title in check for group membership. %s is a user name.
|
||||
$title = sprintf(_("%s's groups"), $this->target->nickname);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:Groups";
|
||||
$link = common_local_url(
|
||||
'usergroups',
|
||||
array('nickname' => $this->target->nickname)
|
||||
);
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Used as subtitle in check for group membership. %1$s is the site name, %2$s is a user name.
|
||||
_('%1$s groups %2$s is a member of.'),
|
||||
$sitename,
|
||||
$this->target->nickname
|
||||
);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlGroups($this->groups);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssGroups($this->groups, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_local_url('ApiGroupList', array('id'=>$this->target->id, 'format'=>'atom'));
|
||||
$this->showAtomGroups(
|
||||
$this->groups,
|
||||
$title,
|
||||
$id,
|
||||
$link,
|
||||
$subtitle,
|
||||
$selfuri
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonGroups($this->groups);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups
|
||||
*
|
||||
* @return array groups
|
||||
*/
|
||||
function getGroups()
|
||||
{
|
||||
$groups = array();
|
||||
|
||||
$group = $this->target->getGroups(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($group->fetch()) {
|
||||
$groups[] = clone($group);
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest group the user has joined
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->groups) && (count($this->groups) > 0)) {
|
||||
return strtotime($this->groups[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last group the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->groups) && (count($this->groups) > 0)) {
|
||||
|
||||
$last = count($this->groups) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->groups[0]->created),
|
||||
strtotime($this->groups[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the newest groups
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns of the lastest 20 groups for the site
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupListAllAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $groups = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->getTargetUser(null);
|
||||
$this->groups = $this->getGroups();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the user's groups
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Message is used as a title when listing the lastest 20 groups. %s is a site name.
|
||||
$title = sprintf(_("%s groups"), $sitename);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:Groups";
|
||||
$link = common_local_url('groups');
|
||||
// TRANS: Message is used as a subtitle when listing the latest 20 groups. %s is a site name.
|
||||
$subtitle = sprintf(_("groups on %s"), $sitename);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlGroups($this->groups);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssGroups($this->groups, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() .
|
||||
'api/statusnet/groups/list_all.atom';
|
||||
$this->showAtomGroups(
|
||||
$this->groups,
|
||||
$title,
|
||||
$id,
|
||||
$link,
|
||||
$subtitle,
|
||||
$selfuri
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonGroups($this->groups);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups
|
||||
*
|
||||
* @return array groups
|
||||
*/
|
||||
function getGroups()
|
||||
{
|
||||
$qry = 'SELECT user_group.* '.
|
||||
'from user_group join local_group on user_group.id = local_group.group_id '.
|
||||
'order by created desc ';
|
||||
$offset = intval($this->page - 1) * intval($this->count);
|
||||
$limit = intval($this->count);
|
||||
if (common_config('db', 'type') == 'pgsql') {
|
||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
} else {
|
||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||
}
|
||||
$group = new User_group();
|
||||
|
||||
$group->query($qry);
|
||||
|
||||
$groups = array();
|
||||
while ($group->fetch()) {
|
||||
$groups[] = clone($group);
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the site's latest group
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->groups) && (count($this->groups) > 0)) {
|
||||
return strtotime($this->groups[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the first and last group the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->groups) && (count($this->groups) > 0)) {
|
||||
|
||||
$last = count($this->groups) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
strtotime($this->groups[0]->created),
|
||||
strtotime($this->groups[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List a group's members
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* List 20 newest members of the group specified by name or ID.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupMembershipAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed trying to show group membership on a non-existing group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the members of the group
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// XXX: RSS and Atom
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUsers($this->profiles);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonUsers($this->profiles);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the members of a group
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
function getProfiles()
|
||||
{
|
||||
$profiles = array();
|
||||
|
||||
$profile = $this->group->getMembers(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$profiles[] = clone($profile);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this list of profiles last modified?
|
||||
*
|
||||
* @return string datestamp of the lastest profile in the group
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language
|
||||
* the group id, and timestamps of the first and last
|
||||
* user who has joined the group
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update a group's 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 API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* API analog to the group edit page
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupProfileUpdateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||
|
||||
$this->fullname = $this->trimmed('fullname');
|
||||
$this->homepage = $this->trimmed('homepage');
|
||||
$this->description = $this->trimmed('description');
|
||||
$this->location = $this->trimmed('location');
|
||||
$this->aliasstring = $this->trimmed('aliases');
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* See which request params have been set, and update the profile
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed when not providing a user or an invalid user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed when not providing a group or an invalid group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
if (!$this->user->isAdmin($this->group)) {
|
||||
// TRANS: Client error displayed when trying to edit a group without being an admin.
|
||||
$this->clientError(_('You must be an admin to edit the group.'), 403);
|
||||
}
|
||||
|
||||
$this->group->query('BEGIN');
|
||||
|
||||
$orig = clone($this->group);
|
||||
|
||||
try {
|
||||
|
||||
if (common_config('profile', 'changenick') == true && $this->group->nickname !== $this->nickname) {
|
||||
try {
|
||||
$this->group->nickname = Nickname::normalize($this->nickname, true);
|
||||
} catch (NicknameException $e) {
|
||||
throw new ApiValidationException($e->getMessage());
|
||||
}
|
||||
$this->group->mainpage = common_local_url('showgroup',
|
||||
array('nickname' => $this->group->nickname));
|
||||
}
|
||||
|
||||
if (!empty($this->fullname)) {
|
||||
$this->validateFullname();
|
||||
$this->group->fullname = $this->fullname;
|
||||
}
|
||||
|
||||
if (!empty($this->homepage)) {
|
||||
$this->validateHomepage();
|
||||
$this->group->homepage = $this->homepage;
|
||||
}
|
||||
|
||||
if (!empty($this->description)) {
|
||||
$this->validateDescription();
|
||||
$this->group->description = $this->decription;
|
||||
}
|
||||
|
||||
if (!empty($this->location)) {
|
||||
$this->validateLocation();
|
||||
$this->group->location = $this->location;
|
||||
}
|
||||
|
||||
} catch (ApiValidationException $ave) {
|
||||
$this->clientError($ave->getMessage(), 400);
|
||||
}
|
||||
|
||||
$result = $this->group->update($orig);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($this->group, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error displayed when group update fails.
|
||||
$this->serverError(_('Could not update group.'));
|
||||
}
|
||||
|
||||
$aliases = array();
|
||||
|
||||
try {
|
||||
if (!empty($this->aliasstring)) {
|
||||
$aliases = $this->validateAliases();
|
||||
}
|
||||
} catch (ApiValidationException $ave) {
|
||||
$this->clientError($ave->getMessage(), 403);
|
||||
}
|
||||
|
||||
$result = $this->group->setAliases($aliases);
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server error displayed when adding group aliases fails.
|
||||
$this->serverError(_('Could not create aliases.'));
|
||||
}
|
||||
|
||||
$this->group->query('COMMIT');
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
function validateHomepage()
|
||||
{
|
||||
if (!is_null($this->homepage)
|
||||
&& (strlen($this->homepage) > 0)
|
||||
&& !common_valid_http_url($this->homepage)) {
|
||||
throw new ApiValidationException(
|
||||
// TRANS: API validation exception thrown when homepage URL does not validate.
|
||||
_('Homepage is not a valid URL.')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function validateFullname()
|
||||
{
|
||||
if (!is_null($this->fullname) && mb_strlen($this->fullname) > 255) {
|
||||
throw new ApiValidationException(
|
||||
// TRANS: API validation exception thrown when full name does not validate.
|
||||
_('Full name is too long (maximum 255 characters).')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function validateDescription()
|
||||
{
|
||||
if (User_group::descriptionTooLong($this->description)) {
|
||||
// TRANS: API validation exception thrown when description does not validate.
|
||||
// TRANS: %d is the maximum description length and used for plural.
|
||||
throw new ApiValidationException(sprintf(_m('Description is too long (maximum %d character).',
|
||||
'Description is too long (maximum %d characters).',
|
||||
User_group::maxDescription()),
|
||||
User_group::maxDescription()));
|
||||
}
|
||||
}
|
||||
|
||||
function validateLocation()
|
||||
{
|
||||
if (!is_null($this->location) && mb_strlen($this->location) > 255) {
|
||||
throw new ApiValidationException(
|
||||
// TRANS: API validation exception thrown when location does not validate.
|
||||
_('Location is too long (maximum 255 characters).')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function validateAliases()
|
||||
{
|
||||
try {
|
||||
$aliases = array_map(array('Nickname', 'normalize'),
|
||||
array_unique(preg_split('/[\s,]+/', $this->aliasstring)));
|
||||
} catch (NicknameException $e) {
|
||||
throw new ApiValidationException(sprintf('Error processing aliases: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
if (count($aliases) > common_config('group', 'maxaliases')) {
|
||||
// TRANS: API validation exception thrown when aliases do not validate.
|
||||
// TRANS: %d is the maximum number of aliases and used for plural.
|
||||
throw new ApiValidationException(sprintf(_m('Too many aliases! Maximum %d allowed.',
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));
|
||||
}
|
||||
|
||||
return $aliases;
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show information about a group
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs detailed information about the group specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Michele <macno@macno.org>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
if (empty($this->group)) {
|
||||
$alias = Group_alias::getKV(
|
||||
'alias',
|
||||
common_canonical_nickname($this->arg('id'))
|
||||
);
|
||||
if (!empty($alias)) {
|
||||
$args = array('id' => $alias->group_id, 'format' => $this->format);
|
||||
common_redirect(common_local_url('ApiGroupShow', $args), 301);
|
||||
} else {
|
||||
// TRANS: Client error displayed when trying to show a group that could not be found.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this group last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->group)) {
|
||||
return strtotime($this->group->modified);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this group
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the notice
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->group)) {
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->group->modified))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Test that you can connect to the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiHelpTestAction extends ApiPrivateAuthAction
|
||||
{
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->element('ok', null, 'true');
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
print '"ok"';
|
||||
$this->endDocument('json');
|
||||
} else {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
throw new ClientException(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show, update or delete a list.
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class ApiListAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* The list in question in the current request
|
||||
*/
|
||||
var $list = null;
|
||||
|
||||
/**
|
||||
* Is this an update request?
|
||||
*/
|
||||
var $update = false;
|
||||
|
||||
/**
|
||||
* Is this a delete request?
|
||||
*/
|
||||
var $delete = false;
|
||||
|
||||
/**
|
||||
* Set the flags for handling the request. Show list if this is a GET
|
||||
* request, update it if it is POST, delete list if method is DELETE
|
||||
* or if method is POST and an argument _method is set to DELETE. Act
|
||||
* like we don't know if the current user has no access to the list.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* - id: the id of the tag or the tag itself
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->delete = ($_SERVER['REQUEST_METHOD'] == 'DELETE' ||
|
||||
($this->trimmed('_method') == 'DELETE' &&
|
||||
$_SERVER['REQUEST_METHOD'] == 'POST'));
|
||||
|
||||
// update list if method is POST or PUT and $this->delete is not true
|
||||
$this->update = (!$this->delete &&
|
||||
in_array($_SERVER['REQUEST_METHOD'], array('POST', 'PUT')));
|
||||
|
||||
$this->user = $this->getTargetUser($this->arg('user'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
// TRANS: Client error displayed when referring to a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if($this->delete) {
|
||||
$this->handleDelete();
|
||||
return true;
|
||||
}
|
||||
|
||||
if($this->update) {
|
||||
$this->handlePut();
|
||||
return true;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* require authentication if it is a write action or user is ambiguous
|
||||
*
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
return parent::requiresAuth() ||
|
||||
$this->create || $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handlePut()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
// TRANS: Client error displayed when trying to update another user's list.
|
||||
$this->clientError(_('You cannot update lists that do not belong to you.'), 401);
|
||||
}
|
||||
|
||||
$new_list = clone($this->list);
|
||||
$new_list->tag = common_canonical_tag($this->arg('name'));
|
||||
$new_list->description = common_canonical_tag($this->arg('description'));
|
||||
$new_list->private = ($this->arg('mode') === 'private') ? true : false;
|
||||
|
||||
$result = $new_list->update($this->list);
|
||||
|
||||
if(!$result) {
|
||||
// TRANS: Client error displayed when an unknown error occurs updating a list.
|
||||
$this->clientError(_('An error occured.'), 503);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($new_list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($new_list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handleDelete()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
// TRANS: Client error displayed when trying to delete another user's list.
|
||||
$this->clientError(_('You cannot delete lists that do not belong to you.'), 401);
|
||||
}
|
||||
|
||||
$record = clone($this->list);
|
||||
$this->list->delete();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($record);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($record);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that this resource is not read-only.
|
||||
*
|
||||
* @return boolean is_read-only=false
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was the list (people tag) last updated?
|
||||
*
|
||||
* @return String time_last_modified
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if(!empty($this->list)) {
|
||||
return strtotime($this->list->modified);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last list the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->list)) {
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->list->created),
|
||||
strtotime($this->list->modified))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* API method to check if a user belongs to a list.
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action handler for Twitter list_memeber methods
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
class ApiListMemberAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* Set the flags for handling the request. Show the profile if this
|
||||
* is a GET request AND the profile is a member of the list, add a member
|
||||
* if it is a POST, remove the profile from the list if method is DELETE
|
||||
* or if method is POST and an argument _method is set to DELETE. Act
|
||||
* like we don't know if the current user has no access to the list.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* - list_id: the id of the tag or the tag itself
|
||||
* - id: the id of the member being looked for/added/removed
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('list_id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
// TRANS: Client error displayed when referring to a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when referring to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$arr = array('tagger' => $this->list->tagger,
|
||||
'tag' => $this->list->tag,
|
||||
'tagged' => $this->target->id);
|
||||
$ptag = Profile_tag::pkeyGet($arr);
|
||||
|
||||
if(empty($ptag)) {
|
||||
// TRANS: Client error displayed when referring to a non-list member.
|
||||
$this->clientError(_('The specified user is not a member of this list.'));
|
||||
}
|
||||
|
||||
$user = $this->twitterUserArray($this->target, true);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUser($user, 'user', true);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonUser($user);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List/add/remove list members.
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apilistusers.php';
|
||||
|
||||
class ApiListMembersAction extends ApiListUsersAction
|
||||
{
|
||||
/**
|
||||
* Add a user to a list (tag someone)
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handlePost()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
// TRANS: Client error displayed when trying to add members to a list without having the right to do so.
|
||||
$this->clientError(_('You are not allowed to add members to this list.'), 401);
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when trying to modify list members without specifying them.
|
||||
$this->clientError(_('You must specify a member.'));
|
||||
}
|
||||
|
||||
$result = Profile_tag::setTag($this->auth_user->id,
|
||||
$this->target->id, $this->list->tag);
|
||||
|
||||
if(empty($result)) {
|
||||
// TRANS: Client error displayed when an unknown error occurs viewing list members.
|
||||
$this->clientError(_('An error occured.'), 500);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user from a list (untag someone)
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handleDelete()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
// TRANS: Client error displayed when trying to remove members from a list without having the right to do so.
|
||||
$this->clientError(_('You are not allowed to remove members from this list.'), 401);
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when trying to modify list members without specifying them.
|
||||
$this->clientError(_('You must specify a member.'));
|
||||
}
|
||||
|
||||
$args = array('tagger' => $this->auth_user->id,
|
||||
'tagged' => $this->target->id,
|
||||
'tag' => $this->list->tag);
|
||||
$ptag = Profile_tag::pkeyGet($args);
|
||||
|
||||
if (empty($ptag)) {
|
||||
// TRANS: Client error displayed when trying to remove a list member that is not part of a list.
|
||||
$this->clientError(_('The user you are trying to remove from the list is not a member.'));
|
||||
}
|
||||
|
||||
if (!$ptag->delete()) {
|
||||
// TRANS: Client error displayed when an unknown error occurs viewing list members.
|
||||
$this->clientError(_('An error occured.'), 500);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the members of a list (people tagged)
|
||||
*/
|
||||
function getUsers()
|
||||
{
|
||||
$fn = array($this->list, 'getTagged');
|
||||
list($this->users, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Get a list of lists a user belongs to. (people tags for a user)
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action handler for API method to list lists a user belongs to.
|
||||
* (people tags for a user)
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
class ApiListMembershipsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = array();
|
||||
var $cursor = -1;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
|
||||
/**
|
||||
* Prepare for running the action
|
||||
* Take arguments for running:s
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$user = $this->getTargetUser($this->arg('user'));
|
||||
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
|
||||
$this->getLists();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the lists
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function getLists()
|
||||
{
|
||||
$fn = array($this->target, 'getOtherTags');
|
||||
|
||||
# 20 lists
|
||||
list($this->lists, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array($this->scoped), $this->cursor, 20);
|
||||
}
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List existing lists or create a new list.
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action handler for Twitter list_memeber methods
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
class ApiListsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = null;
|
||||
var $cursor = 0;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
var $create = false;
|
||||
|
||||
/**
|
||||
* Set the flags for handling the request. List lists created by user if this
|
||||
* is a GET request, create a new list if it is a POST request.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* Parameters for POST request
|
||||
* - name: name of the new list (the people tag itself)
|
||||
* - mode: (optional) mode for the new list private/public
|
||||
* - description: (optional) description for the list
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->create = ($_SERVER['REQUEST_METHOD'] == 'POST');
|
||||
|
||||
if (!$this->create) {
|
||||
|
||||
$this->user = $this->getTargetUser($this->arg('user'));
|
||||
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
$this->getLists();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* require authentication if it is a write action or user is ambiguous
|
||||
*
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
return parent::requiresAuth() ||
|
||||
$this->create || $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request:
|
||||
* Show the lists the user has created if the request method is GET
|
||||
* Create a new list by diferring to handlePost() if it is POST.
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if($this->create) {
|
||||
return $this->handlePost();
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handlePost()
|
||||
{
|
||||
$name=$this->arg('name');
|
||||
if(empty($name)) {
|
||||
// mimick twitter
|
||||
// TRANS: Client error displayed when trying to create a list without a name.
|
||||
print _("A list must have a name.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// twitter creates a new list by appending a number to the end
|
||||
// if the list by the given name already exists
|
||||
// it makes more sense to return the existing list instead
|
||||
|
||||
$private = null;
|
||||
if ($this->arg('mode') === 'public') {
|
||||
$private = false;
|
||||
} else if ($this->arg('mode') === 'private') {
|
||||
$private = true;
|
||||
}
|
||||
|
||||
$list = Profile_list::ensureTag($this->auth_user->id,
|
||||
$this->arg('name'),
|
||||
$this->arg('description'),
|
||||
$private);
|
||||
if (empty($list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lists
|
||||
*/
|
||||
function getLists()
|
||||
{
|
||||
$cursor = (int) $this->arg('cursor', -1);
|
||||
|
||||
// twitter fixes count at 20
|
||||
// there is no argument named count
|
||||
$count = 20;
|
||||
$fn = array($this->target, 'getLists');
|
||||
|
||||
list($this->lists,
|
||||
$this->next_cursor,
|
||||
$this->prev_cursor) = Profile_list::getAtCursor($fn, array($this->scoped), $cursor, $count);
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if (!$this->create && !empty($this->lists) && (count($this->lists) > 0)) {
|
||||
return strtotime($this->lists[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of lists
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last list the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!$this->create && !empty($this->lists) && (count($this->lists) > 0)) {
|
||||
|
||||
$last = count($this->lists) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->lists[0]->created),
|
||||
strtotime($this->lists[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check if a user is subscribed to a list
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class ApiListSubscriberAction extends ApiBareAuthAction
|
||||
{
|
||||
var $list = null;
|
||||
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('list_id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$arr = array('profile_tag_id' => $this->list->id,
|
||||
'profile_id' => $this->target->id);
|
||||
$sub = Profile_tag_subscription::pkeyGet($arr);
|
||||
|
||||
if(empty($sub)) {
|
||||
// TRANS: Client error displayed when a membership check for a user is nagative.
|
||||
$this->clientError(_('The specified user is not a subscriber of this list.'));
|
||||
}
|
||||
|
||||
$user = $this->twitterUserArray($this->target, true);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUser($user, 'user', true);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonUser($user);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show/add/remove list subscribers.
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apilistusers.php';
|
||||
|
||||
class ApiListSubscribersAction extends ApiListUsersAction
|
||||
{
|
||||
/**
|
||||
* Subscribe to list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handlePost()
|
||||
{
|
||||
$result = Profile_tag_subscription::add($this->list,
|
||||
$this->auth_user);
|
||||
|
||||
if(empty($result)) {
|
||||
// TRANS: Client error displayed when an unknown error occurs in the list subscribers action.
|
||||
$this->clientError(_('An error occured.'), 500);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
function handleDelete()
|
||||
{
|
||||
$args = array('profile_tag_id' => $this->list->id,
|
||||
'profile_id' => $this->auth_user->id);
|
||||
$ptag = Profile_tag_subscription::pkeyGet($args);
|
||||
|
||||
if(empty($ptag)) {
|
||||
// TRANS: Client error displayed when trying to unsubscribe from a non-subscribed list.
|
||||
$this->clientError(_('You are not subscribed to this list.'));
|
||||
}
|
||||
|
||||
$result = Profile_tag_subscription::remove($this->list, $this->auth_user);
|
||||
|
||||
if (empty($result)) {
|
||||
// TRANS: Client error displayed when an unknown error occurs unsubscribing from a list.
|
||||
$this->clientError(_('An error occured.'), 500);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getUsers()
|
||||
{
|
||||
$fn = array($this->list, 'getSubscribers');
|
||||
list($this->users, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Get a list of lists a user is subscribed to.
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class ApiListSubscriptionsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = array();
|
||||
var $cursor = -1;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$user = $this->getTargetUser($this->arg('user'));
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
$this->getLists();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the lists
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function getLists()
|
||||
{
|
||||
$fn = array($this->target, 'getTagSubscriptions');
|
||||
# 20 lists
|
||||
list($this->lists, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Upload an image via the API
|
||||
*
|
||||
* 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 API
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Upload an image via the API. Returns a shortened URL for the image
|
||||
* to the user. Apparently modelled after a former Twitpic API.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiMediaUploadAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// fallback to xml for older clients etc
|
||||
if (empty($this->format)) {
|
||||
$this->format = 'xml';
|
||||
}
|
||||
if (!in_array($this->format, ['json', 'xml'])) {
|
||||
throw new ClientException('This API call does not support the format '._ve($this->format));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
throw new ClientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
|
||||
try {
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
common_debug('No media file was uploaded to the _FILES array');
|
||||
$fh = tmpfile();
|
||||
if ($this->arg('media')) {
|
||||
common_debug('Found media parameter which we hope contains a media file!');
|
||||
fwrite($fh, $this->arg('media'));
|
||||
} elseif ($this->arg('media_data')) {
|
||||
common_debug('Found media_data parameter which we hope contains a base64-encoded media file!');
|
||||
fwrite($fh, base64_decode($this->arg('media_data')));
|
||||
} else {
|
||||
common_debug('No media|media_data POST parameter was supplied');
|
||||
fclose($fh);
|
||||
throw $e;
|
||||
}
|
||||
common_debug('MediaFile importing the uploaded file with fromFilehandle');
|
||||
$upload = MediaFile::fromFilehandle($fh, $this->scoped);
|
||||
}
|
||||
|
||||
common_debug('MediaFile completed and saved us fileRecord with id=='._ve($upload->fileRecord->id));
|
||||
// Thumbnails will be generated/cached on demand when accessed (such as with /attachment/:id/thumbnail)
|
||||
$this->showResponse($upload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a Twitpic-like response with the ID of the media file
|
||||
* and a (hopefully) shortened URL for it.
|
||||
*
|
||||
* @param MediaFile $upload the uploaded file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function showResponse(MediaFile $upload)
|
||||
{
|
||||
$this->initDocument($this->format);
|
||||
switch ($this->format) {
|
||||
case 'json':
|
||||
return $this->showResponseJson($upload);
|
||||
case 'xml':
|
||||
return $this->showResponseXml($upload);
|
||||
default:
|
||||
throw new ClientException('This API call does not support the format '._ve($this->format));
|
||||
}
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
|
||||
protected function showResponseJson(MediaFile $upload)
|
||||
{
|
||||
$enc = $upload->fileRecord->getEnclosure();
|
||||
|
||||
// note that we use media_id instead of mediaid which XML users might've gotten used to (nowadays we service media_id in both!)
|
||||
$output = [
|
||||
'media_id' => $upload->fileRecord->id,
|
||||
'media_id_string' => (string)$upload->fileRecord->id,
|
||||
'media_url' => $upload->shortUrl(),
|
||||
'size' => $upload->fileRecord->size,
|
||||
];
|
||||
if (common_get_mime_media($enc->mimetype) === 'image') {
|
||||
$output['image'] = [
|
||||
'w' => $enc->width,
|
||||
'h' => $enc->height,
|
||||
'image_type' => $enc->mimetype,
|
||||
];
|
||||
}
|
||||
print json_encode($output);
|
||||
}
|
||||
|
||||
protected function showResponseXml(MediaFile $upload)
|
||||
{
|
||||
$this->elementStart('rsp', array('stat' => 'ok', 'xmlns:atom'=>Activity::ATOM));
|
||||
$this->element('mediaid', null, $upload->fileRecord->id);
|
||||
$this->element('mediaurl', null, $upload->shortUrl());
|
||||
$this->element('media_url', null, $upload->shortUrl());
|
||||
$this->element('size', null, $upload->fileRecord->size);
|
||||
|
||||
$enclosure = $upload->fileRecord->getEnclosure();
|
||||
$this->element('atom:link', array('rel' => 'enclosure',
|
||||
'href' => $enclosure->url,
|
||||
'type' => $enclosure->mimetype));
|
||||
|
||||
// Twitter specific metadata expected in response since Twitter's Media upload API v1.1 (even though Twitter doesn't use XML)
|
||||
$this->element('media_id', null, $upload->fileRecord->id);
|
||||
$this->element('media_id_string', null, (string)$upload->fileRecord->id);
|
||||
if (common_get_mime_media($enclosure->mimetype) === 'image') {
|
||||
$this->element('image', ['w'=>$enclosure->width, 'h'=>$enclosure->height, 'image_type'=>$enclosure->mimetype]);
|
||||
}
|
||||
$this->elementEnd('rsp');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrided clientError to show a more Twitpic-like error
|
||||
*
|
||||
* @param String $msg an error message
|
||||
*/
|
||||
function clientError($msg, $code=400, $format=null)
|
||||
{
|
||||
$this->initDocument($this->format);
|
||||
switch ($this->format) {
|
||||
case 'json':
|
||||
$error = ['errors' => array()];
|
||||
$error['errors'][] = ['message'=>$msg, 'code'=>131];
|
||||
print json_encode($error);
|
||||
break;
|
||||
case 'xml':
|
||||
$this->elementStart('rsp', array('stat' => 'fail'));
|
||||
|
||||
// @todo add in error code
|
||||
$errAttr = array('msg' => $msg);
|
||||
|
||||
$this->element('err', $errAttr, null);
|
||||
$this->elementEnd('rsp');
|
||||
break;
|
||||
}
|
||||
$this->endDocument($this->format);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for getting OAuth token credentials (exchange an authorized
|
||||
* request token for an access token)
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Action for getting OAuth token credentials (exchange an authorized
|
||||
* request token for an access token)
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiOAuthAccessTokenAction extends ApiOAuthAction
|
||||
{
|
||||
protected $reqToken = null;
|
||||
protected $verifier = null;
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$datastore = new ApiGNUsocialOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
$atok = $app = null;
|
||||
|
||||
// XXX: Insist that oauth_token and oauth_verifier be populated?
|
||||
// Spec doesn't say they MUST be.
|
||||
|
||||
try {
|
||||
$req = OAuthRequest::from_request();
|
||||
|
||||
$this->reqToken = $req->get_parameter('oauth_token');
|
||||
$this->verifier = $req->get_parameter('oauth_verifier');
|
||||
|
||||
$app = $datastore->getAppByRequestToken($this->reqToken);
|
||||
$atok = $server->fetch_access_token($req);
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
|
||||
common_debug(var_export($req, true));
|
||||
$code = $e->getCode();
|
||||
$this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
|
||||
}
|
||||
|
||||
if (empty($atok)) {
|
||||
// Token exchange failed -- log it
|
||||
|
||||
$msg = sprintf(
|
||||
'API OAuth - Failure exchanging OAuth request token for access token, '
|
||||
. 'request token = %s, verifier = %s',
|
||||
$this->reqToken,
|
||||
$this->verifier
|
||||
);
|
||||
|
||||
common_log(LOG_WARNING, $msg);
|
||||
// TRANS: Client error given from the OAuth API when the request token or verifier is invalid.
|
||||
$this->clientError(_('Invalid request token or verifier.'), 400, 'text');
|
||||
} else {
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
"Issued access token '%s' for application %d (%s).",
|
||||
$atok->key,
|
||||
$app->id,
|
||||
$app->name
|
||||
)
|
||||
);
|
||||
$this->showAccessToken($atok);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Display OAuth token credentials
|
||||
*
|
||||
* @param OAuthToken token the access token
|
||||
*/
|
||||
function showAccessToken($token)
|
||||
{
|
||||
header('Content-Type: application/x-www-form-urlencoded');
|
||||
print $token;
|
||||
}
|
||||
}
|
||||
@@ -1,707 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Authorize an OAuth request token
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010-2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize an OAuth request token
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiOAuthAuthorizeAction extends ApiOAuthAction
|
||||
{
|
||||
var $oauthTokenParam;
|
||||
var $reqToken;
|
||||
var $callback;
|
||||
var $app;
|
||||
var $nickname;
|
||||
var $password;
|
||||
var $store;
|
||||
|
||||
/**
|
||||
* Is this a read-only action?
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
$this->password = $this->arg('password');
|
||||
$this->oauthTokenParam = $this->arg('oauth_token');
|
||||
$this->mode = $this->arg('mode');
|
||||
$this->store = new ApiGNUsocialOAuthDataStore();
|
||||
|
||||
try {
|
||||
$this->app = $this->store->getAppByRequestToken($this->oauthTokenParam);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle input, produce output
|
||||
*
|
||||
* Switches on request method; either shows the form or handles its input.
|
||||
*
|
||||
* @param array $args $_REQUEST data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
$this->handlePost();
|
||||
|
||||
} else {
|
||||
|
||||
// Make sure a oauth_token parameter was provided
|
||||
if (empty($this->oauthTokenParam)) {
|
||||
// TRANS: Client error given when no oauth_token was passed to the OAuth API.
|
||||
$this->clientError(_('No oauth_token parameter provided.'));
|
||||
} else {
|
||||
|
||||
// Check to make sure the token exists
|
||||
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
|
||||
|
||||
if (empty($this->reqToken)) {
|
||||
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
|
||||
$this->clientError(_('Invalid request token.'));
|
||||
} else {
|
||||
|
||||
// Check to make sure we haven't already authorized the token
|
||||
if ($this->reqToken->state != 0) {
|
||||
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
|
||||
$this->clientError(_('Request token already authorized.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure there's an app associated with this token
|
||||
if (empty($this->app)) {
|
||||
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
|
||||
$this->clientError(_('Invalid request token.'));
|
||||
}
|
||||
|
||||
$name = $this->app->name;
|
||||
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
// check session token for CSRF protection.
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(
|
||||
// TRANS: Form validation error in API OAuth authorisation because of an invalid session token.
|
||||
_('There was a problem with your session token. Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// check creds
|
||||
|
||||
$user = null;
|
||||
|
||||
if (!common_logged_in()) {
|
||||
|
||||
// XXX Force credentials check?
|
||||
|
||||
// @fixme this should probably use a unified login form handler
|
||||
$user = null;
|
||||
if (Event::handle('StartOAuthLoginCheck', array($this, &$user))) {
|
||||
$user = common_check_user($this->nickname, $this->password);
|
||||
}
|
||||
Event::handle('EndOAuthLoginCheck', array($this, &$user));
|
||||
|
||||
if (empty($user)) {
|
||||
// TRANS: Form validation error given when an invalid username and/or password was passed to the OAuth API.
|
||||
$this->showForm(_("Invalid nickname / password!"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$user = common_current_user();
|
||||
}
|
||||
|
||||
// fetch the token
|
||||
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
|
||||
assert(!empty($this->reqToken));
|
||||
|
||||
if ($this->arg('allow')) {
|
||||
// mark the req token as authorized
|
||||
try {
|
||||
$this->store->authorize_token($this->oauthTokenParam);
|
||||
} catch (Exception $e) {
|
||||
$this->serverError($e->getMessage());
|
||||
}
|
||||
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
"API OAuth - User %d (%s) has authorized request token %s for OAuth application %d (%s).",
|
||||
$user->id,
|
||||
$user->nickname,
|
||||
$this->reqToken->tok,
|
||||
$this->app->id,
|
||||
$this->app->name
|
||||
)
|
||||
);
|
||||
|
||||
$tokenAssoc = new Oauth_token_association();
|
||||
|
||||
$tokenAssoc->profile_id = $user->id;
|
||||
$tokenAssoc->application_id = $this->app->id;
|
||||
$tokenAssoc->token = $this->oauthTokenParam;
|
||||
$tokenAssoc->created = common_sql_now();
|
||||
|
||||
$result = $tokenAssoc->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($tokenAssoc, 'INSERT', __FILE__);
|
||||
// TRANS: Server error displayed when a database action fails.
|
||||
$this->serverError(_('Database error inserting oauth_token_association.'));
|
||||
}
|
||||
|
||||
$callback = $this->getCallback();
|
||||
|
||||
if (!empty($callback) && $this->reqToken->verified_callback != 'oob') {
|
||||
$targetUrl = $this->buildCallbackUrl(
|
||||
$callback,
|
||||
array(
|
||||
'oauth_token' => $this->oauthTokenParam,
|
||||
'oauth_verifier' => $this->reqToken->verifier // 1.0a
|
||||
)
|
||||
);
|
||||
|
||||
common_log(LOG_INFO, "Redirecting to callback: $targetUrl");
|
||||
|
||||
// Redirect the user to the provided OAuth callback
|
||||
common_redirect($targetUrl, 303);
|
||||
|
||||
} elseif ($this->app->type == 2) {
|
||||
// Strangely, a web application seems to want to do the OOB
|
||||
// workflow. Because no callback was specified anywhere.
|
||||
common_log(
|
||||
LOG_WARNING,
|
||||
sprintf(
|
||||
"API OAuth - No callback provided for OAuth web client ID %s (%s) "
|
||||
. "during authorization step. Falling back to OOB workflow.",
|
||||
$this->app->id,
|
||||
$this->app->name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Otherwise, inform the user that the rt was authorized
|
||||
$this->showAuthorized();
|
||||
} else if ($this->arg('cancel')) {
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
"API OAuth - User %d (%s) refused to authorize request token %s for OAuth application %d (%s).",
|
||||
$user->id,
|
||||
$user->nickname,
|
||||
$this->reqToken->tok,
|
||||
$this->app->id,
|
||||
$this->app->name
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
$this->store->revoke_token($this->oauthTokenParam, 0);
|
||||
} catch (Exception $e) {
|
||||
$this->ServerError($e->getMessage());
|
||||
}
|
||||
|
||||
$callback = $this->getCallback();
|
||||
|
||||
// If there's a callback available, inform the consumer the user
|
||||
// has refused authorization
|
||||
if (!empty($callback) && $this->reqToken->verified_callback != 'oob') {
|
||||
$targetUrl = $this->buildCallbackUrl(
|
||||
$callback,
|
||||
array(
|
||||
'oauth_problem' => 'user_refused',
|
||||
)
|
||||
);
|
||||
|
||||
common_log(LOG_INFO, "Redirecting to callback: $targetUrl");
|
||||
|
||||
// Redirect the user to the provided OAuth callback
|
||||
common_redirect($targetUrl, 303);
|
||||
}
|
||||
|
||||
// otherwise inform the user that authorization for the rt was declined
|
||||
$this->showCanceled();
|
||||
|
||||
} else {
|
||||
// TRANS: Client error given on when invalid data was passed through a form in the OAuth API.
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show body - override to add a special CSS class for the authorize
|
||||
* page's "desktop mode" (minimal display)
|
||||
*
|
||||
* Calls template methods
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showBody()
|
||||
{
|
||||
$bodyClasses = array();
|
||||
|
||||
if ($this->desktopMode()) {
|
||||
$bodyClasses[] = 'oauth-desktop-mode';
|
||||
}
|
||||
|
||||
if (common_current_user()) {
|
||||
$bodyClasses[] = 'user_in';
|
||||
}
|
||||
|
||||
$attrs = array('id' => strtolower($this->trimmed('action')));
|
||||
|
||||
if (!empty($bodyClasses)) {
|
||||
$attrs['class'] = implode(' ', $bodyClasses);
|
||||
}
|
||||
|
||||
$this->elementStart('body', $attrs);
|
||||
|
||||
$this->elementStart('div', array('id' => 'wrap'));
|
||||
if (Event::handle('StartShowHeader', array($this))) {
|
||||
$this->showHeader();
|
||||
Event::handle('EndShowHeader', array($this));
|
||||
}
|
||||
$this->showCore();
|
||||
if (Event::handle('StartShowFooter', array($this))) {
|
||||
$this->showFooter();
|
||||
Event::handle('EndShowFooter', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
$this->showScripts();
|
||||
$this->elementEnd('body');
|
||||
}
|
||||
|
||||
function showForm($error=null)
|
||||
{
|
||||
$this->error = $error;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showScripts()
|
||||
{
|
||||
parent::showScripts();
|
||||
if (!common_logged_in()) {
|
||||
$this->autofocus('nickname');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
function title()
|
||||
{
|
||||
// TRANS: Title for a page where a user can confirm/deny account access by an external application.
|
||||
return _('An application would like to connect to your account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the authorization form.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_apioauthauthorize',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('ApiOAuthAuthorize')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', array('id' => 'apioauthauthorize_allowdeny'),
|
||||
// TRANS: Fieldset legend.
|
||||
_('Allow or deny access'));
|
||||
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->hidden('mode', $this->mode);
|
||||
$this->hidden('oauth_token', $this->oauthTokenParam);
|
||||
$this->hidden('oauth_callback', $this->callback);
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->elementStart('p');
|
||||
if (!empty($this->app->icon) && $this->app->name != 'anonymous') {
|
||||
$this->element('img', array('src' => $this->app->icon));
|
||||
}
|
||||
|
||||
$access = ($this->app->access_type & Oauth_application::$writeAccess) ?
|
||||
'access and update' : 'access';
|
||||
|
||||
if ($this->app->name == 'anonymous') {
|
||||
// Special message for the anonymous app and consumer.
|
||||
// TRANS: User notification of external application requesting account access.
|
||||
// TRANS: %3$s is the access type requested (read-write or read-only), %4$s is the StatusNet sitename.
|
||||
$msg = _('An application would like the ability ' .
|
||||
'to <strong>%3$s</strong> your %4$s account data. ' .
|
||||
'You should only give access to your %4$s account ' .
|
||||
'to third parties you trust.');
|
||||
} else {
|
||||
// TRANS: User notification of external application requesting account access.
|
||||
// TRANS: %1$s is the application name requesting access, %2$s is the organisation behind the application,
|
||||
// TRANS: %3$s is the access type requested, %4$s is the StatusNet sitename.
|
||||
$msg = _('The application <strong>%1$s</strong> by ' .
|
||||
'<strong>%2$s</strong> would like the ability ' .
|
||||
'to <strong>%3$s</strong> your %4$s account data. ' .
|
||||
'You should only give access to your %4$s account ' .
|
||||
'to third parties you trust.');
|
||||
}
|
||||
|
||||
$this->raw(sprintf($msg,
|
||||
$this->app->name,
|
||||
$this->app->organization,
|
||||
$access,
|
||||
common_config('site', 'name')));
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
// quickie hack
|
||||
$button = false;
|
||||
if (!common_logged_in()) {
|
||||
if (Event::handle('StartOAuthLoginForm', array($this, &$button))) {
|
||||
$this->elementStart('fieldset');
|
||||
// TRANS: Fieldset legend.
|
||||
$this->element('legend', null, _m('LEGEND','Account'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label on OAuth API authorisation form.
|
||||
$this->input('nickname', _('Nickname'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label on OAuth API authorisation form.
|
||||
$this->password('password', _('Password'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
}
|
||||
Event::handle('EndOAuthLoginForm', array($this, &$button));
|
||||
}
|
||||
|
||||
$this->element('input', array('id' => 'cancel_submit',
|
||||
'class' => 'submit submit form_action-primary',
|
||||
'name' => 'cancel',
|
||||
'type' => 'submit',
|
||||
// TRANS: Button text that when clicked will cancel the process of allowing access to an account
|
||||
// TRANS: by an external application.
|
||||
'value' => _m('BUTTON','Cancel')));
|
||||
|
||||
$this->element('input', array('id' => 'allow_submit',
|
||||
'class' => 'submit submit form_action-secondary',
|
||||
'name' => 'allow',
|
||||
'type' => 'submit',
|
||||
// TRANS: Button text that when clicked will allow access to an account by an external application.
|
||||
'value' => $button ? $button : _m('BUTTON','Allow')));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for using the form
|
||||
*
|
||||
* For "remembered" logins, we make the user re-login when they
|
||||
* try to change settings. Different instructions for this case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Form instructions.
|
||||
return _('Authorize access to your account information.');
|
||||
}
|
||||
|
||||
/**
|
||||
* A local menu
|
||||
*
|
||||
* Shows different login/register actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showLocalNav()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if a the "mode" parameter is present in the request
|
||||
* and set to "desktop". If it is, the page is meant to be displayed in
|
||||
* a small frame of another application, and we should suppress the
|
||||
* header, aside, and footer.
|
||||
*/
|
||||
function desktopMode()
|
||||
{
|
||||
if (isset($this->mode) && $this->mode == 'desktop') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showHeader()
|
||||
{
|
||||
if ($this->desktopMode() == false) {
|
||||
parent::showHeader();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showAside()
|
||||
{
|
||||
if ($this->desktopMode() == false) {
|
||||
parent::showAside();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showFooter()
|
||||
{
|
||||
if ($this->desktopMode() == false) {
|
||||
parent::showFooter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show site notice.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showSiteNotice()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notice form.
|
||||
*
|
||||
* Show the form for posting a new notice
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showNoticeForm()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/*
|
||||
* Show a nice message confirming the authorization
|
||||
* operation was canceled.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showCanceled()
|
||||
{
|
||||
$info = new InfoAction(
|
||||
// TRANS: Header for user notification after revoking OAuth access to an application.
|
||||
_('Authorization canceled.'),
|
||||
sprintf(
|
||||
// TRANS: User notification after revoking OAuth access to an application.
|
||||
// TRANS: %s is an OAuth token.
|
||||
_('The request token %s has been revoked.'),
|
||||
$this->oauthTokenParam
|
||||
)
|
||||
);
|
||||
|
||||
$info->showPage();
|
||||
}
|
||||
|
||||
/*
|
||||
* Show a nice message that the authorization was successful.
|
||||
* If the operation is out-of-band, show a pin.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showAuthorized()
|
||||
{
|
||||
$title = null;
|
||||
$msg = null;
|
||||
|
||||
if ($this->app->name == 'anonymous') {
|
||||
|
||||
$title =
|
||||
// TRANS: Title of the page notifying the user that an anonymous client application was successfully authorized to access the user's account with OAuth.
|
||||
_('You have successfully authorized the application');
|
||||
|
||||
$msg =
|
||||
// TRANS: Message notifying the user that an anonymous client application was successfully authorized to access the user's account with OAuth.
|
||||
_('Please return to the application and enter the following security code to complete the process.');
|
||||
|
||||
} else {
|
||||
|
||||
$title = sprintf(
|
||||
// TRANS: Title of the page notifying the user that the client application was successfully authorized to access the user's account with OAuth.
|
||||
// TRANS: %s is the authorised application name.
|
||||
_('You have successfully authorized %s'),
|
||||
$this->app->name
|
||||
);
|
||||
|
||||
$msg = sprintf(
|
||||
// TRANS: Message notifying the user that the client application was successfully authorized to access the user's account with OAuth.
|
||||
// TRANS: %s is the authorised application name.
|
||||
_('Please return to %s and enter the following security code to complete the process.'),
|
||||
$this->app->name
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ($this->reqToken->verified_callback == 'oob') {
|
||||
$pin = new ApiOAuthPinAction(
|
||||
$title,
|
||||
$msg,
|
||||
$this->reqToken->verifier,
|
||||
$this->desktopMode()
|
||||
);
|
||||
$pin->showPage();
|
||||
} else {
|
||||
// NOTE: This would only happen if an application registered as
|
||||
// a web application but sent in 'oob' for the oauth_callback
|
||||
// parameter. Usually web apps will send in a callback and
|
||||
// not use the pin-based workflow.
|
||||
|
||||
$info = new InfoAction(
|
||||
$title,
|
||||
$msg,
|
||||
$this->oauthTokenParam,
|
||||
$this->reqToken->verifier
|
||||
);
|
||||
|
||||
$info->showPage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out what the callback should be
|
||||
*/
|
||||
function getCallback()
|
||||
{
|
||||
$callback = null;
|
||||
|
||||
// Return the verified callback if we have one
|
||||
if ($this->reqToken->verified_callback != 'oob') {
|
||||
|
||||
$callback = $this->reqToken->verified_callback;
|
||||
|
||||
// Otherwise return the callback that was provided when
|
||||
// registering the app
|
||||
if (empty($callback)) {
|
||||
|
||||
common_debug(
|
||||
"No verified callback found for request token, using application callback: "
|
||||
. $this->app->callback_url,
|
||||
__FILE__
|
||||
);
|
||||
|
||||
$callback = $this->app->callback_url;
|
||||
}
|
||||
}
|
||||
|
||||
return $callback;
|
||||
}
|
||||
|
||||
/*
|
||||
* Properly format the callback URL and parameters so it's
|
||||
* suitable for a redirect in the OAuth dance
|
||||
*
|
||||
* @param string $url the URL
|
||||
* @param array $params an array of parameters
|
||||
*
|
||||
* @return string $url a URL to use for redirecting to
|
||||
*/
|
||||
function buildCallbackUrl($url, $params)
|
||||
{
|
||||
foreach ($params as $k => $v) {
|
||||
$url = $this->appendQueryVar(
|
||||
$url,
|
||||
OAuthUtil::urlencode_rfc3986($k),
|
||||
OAuthUtil::urlencode_rfc3986($v)
|
||||
);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a new query parameter after any existing query
|
||||
* parameters.
|
||||
*
|
||||
* @param string $url the URL
|
||||
* @prarm string $k the parameter name
|
||||
* @param string $v value of the paramter
|
||||
*
|
||||
* @return string $url the new URL with added parameter
|
||||
*/
|
||||
function appendQueryVar($url, $k, $v) {
|
||||
$url = preg_replace('/(.*)(\?|&)' . $k . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
|
||||
$url = substr($url, 0, -1);
|
||||
if (strpos($url, '?') === false) {
|
||||
return ($url . '?' . $k . '=' . $v);
|
||||
} else {
|
||||
return ($url . '&' . $k . '=' . $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for displaying an OAuth verifier pin
|
||||
*
|
||||
* 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 Action
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for displaying an OAuth verifier pin
|
||||
*
|
||||
* XXX: I'm pretty sure we don't need to check the logged in state here. -- Zach
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiOAuthPinAction extends InfoAction
|
||||
{
|
||||
function __construct($title, $message, $verifier, $desktopMode = false)
|
||||
{
|
||||
$this->verifier = $verifier;
|
||||
$this->title = $title;
|
||||
$this->desktopMode = $desktopMode;
|
||||
parent::__construct($title, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show body - override to add a special CSS class for the pin pages's
|
||||
* "desktop mode" (minimal display)
|
||||
*
|
||||
* Calls template methods
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showBody()
|
||||
{
|
||||
$bodyClasses = array();
|
||||
|
||||
if ($this->desktopMode) {
|
||||
$bodyClasses[] = 'oauth-desktop-mode';
|
||||
}
|
||||
|
||||
if (common_current_user()) {
|
||||
$bodyClasses[] = 'user_in';
|
||||
}
|
||||
|
||||
$attrs = array('id' => strtolower($this->trimmed('action')));
|
||||
|
||||
if (!empty($bodyClasses)) {
|
||||
$attrs['class'] = implode(' ', $bodyClasses);
|
||||
}
|
||||
|
||||
$this->elementStart('body', $attrs);
|
||||
|
||||
$this->elementStart('div', array('id' => 'wrap'));
|
||||
if (Event::handle('StartShowHeader', array($this))) {
|
||||
$this->showHeader();
|
||||
Event::handle('EndShowHeader', array($this));
|
||||
}
|
||||
$this->showCore();
|
||||
if (Event::handle('StartShowFooter', array($this))) {
|
||||
$this->showFooter();
|
||||
Event::handle('EndShowFooter', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
$this->showScripts();
|
||||
$this->elementEnd('body');
|
||||
}
|
||||
|
||||
/**
|
||||
* A local menu
|
||||
*
|
||||
* Shows different login/register actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showLocalNav()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showHeader()
|
||||
{
|
||||
if ($this->desktopMode == false) {
|
||||
parent::showHeader();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showAside()
|
||||
{
|
||||
if ($this->desktopMode == false) {
|
||||
parent::showAside();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showFooter()
|
||||
{
|
||||
if ($this->desktopMode == false) {
|
||||
parent::showFooter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show site notice.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showSiteNotice()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notice form.
|
||||
*
|
||||
* Show the form for posting a new notice
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showNoticeForm()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Display content.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
$this->element('div', array('class' => 'info'), $this->message);
|
||||
$this->element('div', array('id' => 'oauth_pin'), $this->verifier);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Issue temporary OAuth credentials (a request token)
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue temporary OAuth credentials (a request token)
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiOAuthRequestTokenAction extends ApiOAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// XXX: support "force_login" parameter like Twitter? (Forces the user to enter
|
||||
// their credentials to ensure the correct users account is authorized.)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request for temporary OAuth credentials
|
||||
*
|
||||
* Make sure the request is kosher, then emit a set of temporary
|
||||
* credentials -- AKA an unauthorized request token.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$datastore = new ApiGNUsocialOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
try {
|
||||
|
||||
$req = OAuthRequest::from_request();
|
||||
|
||||
// verify callback
|
||||
if (!$this->verifyCallback($req->get_parameter('oauth_callback'))) {
|
||||
throw new OAuthException(
|
||||
"You must provide a valid URL or 'oob' in oauth_callback.",
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
// check signature and issue a new request token
|
||||
$token = $server->fetch_request_token($req);
|
||||
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
"API OAuth - Issued request token %s for consumer %s with oauth_callback %s",
|
||||
$token->key,
|
||||
$req->get_parameter('oauth_consumer_key'),
|
||||
"'" . $req->get_parameter('oauth_callback') ."'"
|
||||
)
|
||||
);
|
||||
|
||||
// return token to the client
|
||||
$this->showRequestToken($token);
|
||||
|
||||
} catch (OAuthException $e) {
|
||||
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
|
||||
|
||||
// Return 401 for for bad credentials or signature problems,
|
||||
// and 400 for missing or unsupported parameters
|
||||
|
||||
$code = $e->getCode();
|
||||
$this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Display temporary OAuth credentials
|
||||
*/
|
||||
function showRequestToken($token)
|
||||
{
|
||||
header('Content-Type: application/x-www-form-urlencoded');
|
||||
print $token;
|
||||
print '&oauth_callback_confirmed=true';
|
||||
}
|
||||
|
||||
/* Make sure the callback parameter contains either a real URL
|
||||
* or the string 'oob'.
|
||||
*
|
||||
* @todo Check for evil/banned URLs here
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function verifyCallback($callback)
|
||||
{
|
||||
if ($callback == "oob") {
|
||||
common_debug("OAuth request token requested for out of band client.");
|
||||
|
||||
// XXX: Should we throw an error if a client is registered as a
|
||||
// web application but requests the pin based workflow? For now I'm
|
||||
// allowing the workflow to proceed and issuing a pin. --Zach
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return filter_var($callback, FILTER_VALIDATE_URL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,392 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for showing Twitter-like Atom search results
|
||||
*
|
||||
* 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 Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for outputting search results in Twitter compatible Atom
|
||||
* format.
|
||||
*
|
||||
* TODO: abstract Atom stuff into a ruseable base class like
|
||||
* RSS10Action.
|
||||
*
|
||||
* @category Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see ApiPrivateAuthAction
|
||||
*/
|
||||
class ApiSearchAtomAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $cnt;
|
||||
var $query;
|
||||
var $lang;
|
||||
var $rpp;
|
||||
var $page;
|
||||
var $since_id;
|
||||
var $geocode;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Just wraps the Action constructor.
|
||||
*
|
||||
* @param string $output URI to output to, default = stdout
|
||||
* @param boolean $indent Whether to indent output, default true
|
||||
*
|
||||
* @see Action::__construct
|
||||
*/
|
||||
function __construct($output='php://output', $indent=null)
|
||||
{
|
||||
parent::__construct($output, $indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to write to the database?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadonly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read arguments and initialize members
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->query = $this->trimmed('q');
|
||||
$this->lang = $this->trimmed('lang');
|
||||
$this->rpp = $this->trimmed('rpp');
|
||||
|
||||
if (!$this->rpp) {
|
||||
$this->rpp = 15;
|
||||
}
|
||||
|
||||
if ($this->rpp > 100) {
|
||||
$this->rpp = 100;
|
||||
}
|
||||
|
||||
$this->page = $this->trimmed('page');
|
||||
|
||||
if (!$this->page) {
|
||||
$this->page = 1;
|
||||
}
|
||||
|
||||
// TODO: Suppport max_id -- we need to tweak the backend
|
||||
// Search classes to support it.
|
||||
|
||||
$this->since_id = $this->trimmed('since_id');
|
||||
$this->geocode = $this->trimmed('geocode');
|
||||
|
||||
// TODO: Also, language and geocode
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
common_debug("In apisearchatom handle()");
|
||||
$this->showAtom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notices to output as results. This also sets some class
|
||||
* attrs so we can use them to calculate pagination, and output
|
||||
* since_id and max_id.
|
||||
*
|
||||
* @return array an array of Notice objects sorted in reverse chron
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
// TODO: Support search operators like from: and to:, boolean, etc.
|
||||
|
||||
$notices = array();
|
||||
$notice = new Notice();
|
||||
|
||||
// lcase it for comparison
|
||||
$q = strtolower($this->query);
|
||||
|
||||
$search_engine = $notice->getSearchEngine('notice');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
$search_engine->limit(($this->page - 1) * $this->rpp,
|
||||
$this->rpp + 1, true);
|
||||
if (false === $search_engine->query($q)) {
|
||||
$this->cnt = 0;
|
||||
} else {
|
||||
$this->cnt = $notice->find();
|
||||
}
|
||||
|
||||
$cnt = 0;
|
||||
$this->max_id = 0;
|
||||
|
||||
if ($this->cnt > 0) {
|
||||
while ($notice->fetch()) {
|
||||
++$cnt;
|
||||
|
||||
if (!$this->max_id) {
|
||||
$this->max_id = $notice->id;
|
||||
}
|
||||
|
||||
if ($this->since_id && $notice->id <= $this->since_id) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($cnt > $this->rpp) {
|
||||
break;
|
||||
}
|
||||
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output search results as an Atom feed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showAtom()
|
||||
{
|
||||
$notices = $this->getNotices();
|
||||
|
||||
$this->initAtom();
|
||||
$this->showFeed();
|
||||
|
||||
foreach ($notices as $n) {
|
||||
$profile = $n->getProfile();
|
||||
|
||||
// Don't show notices from deleted users
|
||||
|
||||
if (!empty($profile)) {
|
||||
$this->showEntry($n);
|
||||
}
|
||||
}
|
||||
|
||||
$this->endAtom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show feed specific Atom elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showFeed()
|
||||
{
|
||||
// TODO: A9 OpenSearch stuff like search.twitter.com?
|
||||
|
||||
$server = common_config('site', 'server');
|
||||
$sitename = common_config('site', 'name');
|
||||
|
||||
// XXX: Use xmlns:statusnet instead?
|
||||
|
||||
$this->elementStart('feed',
|
||||
array('xmlns' => 'http://www.w3.org/2005/Atom',
|
||||
|
||||
// XXX: xmlns:twitter causes Atom validation to fail
|
||||
// It's used for the source attr on notices
|
||||
|
||||
'xmlns:twitter' => 'http://api.twitter.com/',
|
||||
'xml:lang' => 'en-US')); // XXX Other locales ?
|
||||
|
||||
$taguribase = TagURI::base();
|
||||
$this->element('id', null, "tag:$taguribase:search/$server");
|
||||
|
||||
$site_uri = common_path(false);
|
||||
|
||||
$search_uri = $site_uri . 'api/search.atom?q=' . urlencode($this->query);
|
||||
|
||||
if ($this->rpp != 15) {
|
||||
$search_uri .= '&rpp=' . $this->rpp;
|
||||
}
|
||||
|
||||
// FIXME: this alternate link is not quite right because our
|
||||
// web-based notice search doesn't support a rpp (responses per
|
||||
// page) param yet
|
||||
|
||||
$this->element('link', array('type' => 'text/html',
|
||||
'rel' => 'alternate',
|
||||
'href' => $site_uri . 'search/notice?q=' .
|
||||
urlencode($this->query)));
|
||||
|
||||
// self link
|
||||
|
||||
$self_uri = $search_uri;
|
||||
$self_uri .= ($this->page > 1) ? '&page=' . $this->page : '';
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'self',
|
||||
'href' => $self_uri));
|
||||
|
||||
// @todo Needs i18n?
|
||||
$this->element('title', null, "$this->query - $sitename Search");
|
||||
$this->element('updated', null, common_date_iso8601('now'));
|
||||
|
||||
// XXX: The below "rel" links are not valid Atom, but it's what
|
||||
// Twitter does...
|
||||
|
||||
// refresh link
|
||||
|
||||
$refresh_uri = $search_uri . "&since_id=" . $this->max_id;
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'refresh',
|
||||
'href' => $refresh_uri));
|
||||
|
||||
// pagination links
|
||||
|
||||
if ($this->cnt > $this->rpp) {
|
||||
|
||||
$next_uri = $search_uri . "&max_id=" . $this->max_id .
|
||||
'&page=' . ($this->page + 1);
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'next',
|
||||
'href' => $next_uri));
|
||||
}
|
||||
|
||||
if ($this->page > 1) {
|
||||
|
||||
$previous_uri = $search_uri . "&max_id=" . $this->max_id .
|
||||
'&page=' . ($this->page - 1);
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'previous',
|
||||
'href' => $previous_uri));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an Atom entry similar to search.twitter.com's based on
|
||||
* a given notice
|
||||
*
|
||||
* @param Notice $notice the notice to use
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showEntry($notice)
|
||||
{
|
||||
$server = common_config('site', 'server');
|
||||
$profile = $notice->getProfile();
|
||||
$nurl = common_local_url('shownotice', array('notice' => $notice->id));
|
||||
|
||||
$this->elementStart('entry');
|
||||
|
||||
$taguribase = TagURI::base();
|
||||
|
||||
$this->element('id', null, "tag:$taguribase:$notice->id");
|
||||
$this->element('published', null, common_date_w3dtf($notice->created));
|
||||
$this->element('link', array('type' => 'text/html',
|
||||
'rel' => 'alternate',
|
||||
'href' => $nurl));
|
||||
$this->element('title', null, common_xml_safe_str(trim($notice->content)));
|
||||
$this->element('content', array('type' => 'html'), $notice->getRendered());
|
||||
$this->element('updated', null, common_date_w3dtf($notice->created));
|
||||
$this->element('link', array('type' => 'image/png',
|
||||
// XXX: Twitter uses rel="image" (not valid)
|
||||
'rel' => 'related',
|
||||
'href' => $profile->avatarUrl()));
|
||||
|
||||
// @todo: Here is where we'd put in a link to an atom feed for threads
|
||||
|
||||
$source = null;
|
||||
$source_link = null;
|
||||
|
||||
$ns = $notice->getSource();
|
||||
if ($ns instanceof Notice_source) {
|
||||
$source = $ns->code;
|
||||
if (!empty($ns->url)) {
|
||||
$source_link = $ns->url;
|
||||
if (!empty($ns->name)) {
|
||||
$source = $ns->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->element("twitter:source", null, $source);
|
||||
$this->element("twitter:source_link", null, $source_link);
|
||||
|
||||
$this->elementStart('author');
|
||||
|
||||
$name = $profile->nickname;
|
||||
|
||||
if ($profile->fullname) {
|
||||
// @todo Needs proper i18n?
|
||||
$name .= ' (' . $profile->fullname . ')';
|
||||
}
|
||||
|
||||
$this->element('name', null, $name);
|
||||
$this->element('uri', null, common_profile_uri($profile));
|
||||
$this->elementEnd('author');
|
||||
|
||||
$this->elementEnd('entry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Atom output, send headers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function initAtom()
|
||||
{
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
$this->startXml();
|
||||
}
|
||||
|
||||
/**
|
||||
* End the Atom feed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function endAtom()
|
||||
{
|
||||
$this->elementEnd('feed');
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for showing Twitter-like JSON search results
|
||||
*
|
||||
* 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 Search
|
||||
* @package GNUsocial
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2010 StatusNet, Inc.
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Action handler for Twitter-compatible API search
|
||||
*
|
||||
* @category Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
* @see ApiAction
|
||||
*/
|
||||
class ApiSearchJSONAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $query;
|
||||
var $lang;
|
||||
var $rpp;
|
||||
var $page;
|
||||
var $since_id;
|
||||
var $limit;
|
||||
var $geocode;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean true if nothing goes wrong
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->query = $this->trimmed('q');
|
||||
$this->lang = $this->trimmed('lang');
|
||||
$this->rpp = $this->trimmed('rpp');
|
||||
|
||||
if (!$this->rpp) {
|
||||
$this->rpp = 15;
|
||||
}
|
||||
|
||||
if ($this->rpp > 100) {
|
||||
$this->rpp = 100;
|
||||
}
|
||||
|
||||
$this->page = $this->trimmed('page');
|
||||
|
||||
if (!$this->page) {
|
||||
$this->page = 1;
|
||||
}
|
||||
|
||||
// TODO: Suppport max_id -- we need to tweak the backend
|
||||
// Search classes to support it.
|
||||
|
||||
$this->since_id = $this->trimmed('since_id');
|
||||
$this->geocode = $this->trimmed('geocode');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show search results
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showResults()
|
||||
{
|
||||
// TODO: Support search operators like from: and to:, boolean, etc.
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$this->notices = array();
|
||||
$search_engine = $notice->getSearchEngine('notice');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
$search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1);
|
||||
if ($search_engine->query($this->query)) {
|
||||
$cnt = $notice->find();
|
||||
$this->notices = $notice->fetchAll();
|
||||
}
|
||||
|
||||
$this->showJsonTimeline($this->notices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to write to the database?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Destroy a notice through the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Deletes one of the authenticating user's statuses (notices).
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiStatusesDestroyAction extends ApiAuthAction
|
||||
{
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
|
||||
// TRANS: Client error displayed trying to delete a status not using POST or DELETE.
|
||||
// TRANS: POST and DELETE should not be translated.
|
||||
throw new ClientException(_('This method requires a POST or DELETE.'));
|
||||
}
|
||||
|
||||
// FIXME: Return with a Not Acceptable status code?
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
throw new ClientException(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->notice = Notice::getByID($this->trimmed('id'));
|
||||
} catch (NoResultException $e) {
|
||||
// TRANS: Client error displayed trying to delete a status with an invalid ID.
|
||||
throw new ClientException(_('No status found with that ID.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!$this->scoped->sameAs($this->notice->getProfile()) && !$this->scoped->hasRight(Right::DELETEOTHERSNOTICE)) {
|
||||
// TRANS: Client error displayed trying to delete a status of another user.
|
||||
throw new AuthorizationException(_('You may not delete another user\'s status.'));
|
||||
}
|
||||
|
||||
if (Event::handle('StartDeleteOwnNotice', array($this->scoped->getUser(), $this->notice))) {
|
||||
$this->notice->deleteAs($this->scoped);
|
||||
Event::handle('EndDeleteOwnNotice', array($this->scoped->getUser(), $this->notice));
|
||||
}
|
||||
$this->showNotice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the deleted notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->show_single_json_status($this->notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a notice (as a Twitter-style status)
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Returns the notice specified by id as a Twitter-style status and inline user
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $notice_id = null;
|
||||
var $notice = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// 'id' is an undocumented parameter in Twitter's API. Several
|
||||
// clients make use of it, so we support it too.
|
||||
|
||||
// show.json?id=12345 takes precedence over /show/12345.json
|
||||
|
||||
$this->notice_id = (int)$this->trimmed('id');
|
||||
|
||||
$this->notice = null;
|
||||
try {
|
||||
$this->notice = Notice::getByID($this->notice_id);
|
||||
} catch (NoResultException $e) {
|
||||
// No such notice was found, maybe it was deleted?
|
||||
$deleted = null;
|
||||
Event::handle('IsNoticeDeleted', array($this->notice_id, &$deleted));
|
||||
if ($deleted === true) {
|
||||
// TRANS: Client error displayed trying to show a deleted notice.
|
||||
throw new ClientException(_('Notice deleted.'), 410);
|
||||
}
|
||||
// TRANS: Client error displayed trying to show a non-existing notice.
|
||||
throw new ClientException(_('No such notice.'), 404);
|
||||
}
|
||||
|
||||
if (!$this->notice->inScope($this->scoped)) {
|
||||
// TRANS: Client exception thrown when trying a view a notice the user has no access to.
|
||||
throw new ClientException(_('Access restricted.'), 403);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json', 'atom'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
switch ($_SERVER['REQUEST_METHOD']) {
|
||||
case 'GET':
|
||||
$this->showNotice();
|
||||
break;
|
||||
case 'DELETE':
|
||||
$this->deleteNotice();
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed calling an unsupported HTTP error in API status show.
|
||||
$this->clientError(_('HTTP method not supported.'), 405);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_single_json_status($this->notice);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->showSingleAtomStatus($this->notice);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Exception thrown requesting an unsupported notice output format.
|
||||
// TRANS: %s is the requested output format.
|
||||
throw new Exception(sprintf(_("Unsupported format: %s."), $this->format));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this notice last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
return strtotime($this->notice->created);
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this notice
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the notice
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->notice->id,
|
||||
strtotime($this->notice->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
function deleteNotice()
|
||||
{
|
||||
if ($this->format != 'atom') {
|
||||
// TRANS: Client error displayed when trying to delete a notice not using the Atom format.
|
||||
$this->clientError(_('Can only delete using the Atom format.'));
|
||||
}
|
||||
|
||||
if (empty($this->auth_user) ||
|
||||
($this->notice->profile_id != $this->auth_user->id &&
|
||||
!$this->auth_user->hasRight(Right::DELETEOTHERSNOTICE))) {
|
||||
// TRANS: Client error displayed when a user has no rights to delete notices of other users.
|
||||
$this->clientError(_('Cannot delete this notice.'), 403);
|
||||
}
|
||||
|
||||
if (Event::handle('StartDeleteOwnNotice', array($this->auth_user, $this->notice))) {
|
||||
$this->notice->deleteAs($this->scoped);
|
||||
Event::handle('EndDeleteOwnNotice', array($this->auth_user, $this->notice));
|
||||
}
|
||||
|
||||
// @fixme is there better output we could do here?
|
||||
|
||||
header('HTTP/1.1 200 OK');
|
||||
header('Content-Type: text/plain');
|
||||
// TRANS: Confirmation of notice deletion in API. %d is the ID (number) of the deleted notice.
|
||||
print(sprintf(_('Deleted notice %d'), $this->notice->id));
|
||||
print("\n");
|
||||
}
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Post a notice (update your status) through the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page statusesupdate statuses/update
|
||||
|
||||
@section Description
|
||||
Updates the authenticating user's status. Requires the status parameter specified below.
|
||||
Request must be a POST.
|
||||
|
||||
@par URL pattern
|
||||
/api/statuses/update.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json, atom
|
||||
|
||||
@par HTTP Method(s)
|
||||
POST
|
||||
|
||||
@par Requires Authentication
|
||||
Yes
|
||||
|
||||
@param status (Required) The URL-encoded text of the status update.
|
||||
@param source (Optional) The source application name, if using HTTP authentication or an anonymous OAuth consumer.
|
||||
@param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to.
|
||||
@param lat (Optional) The latitude the status refers to.
|
||||
@param long (Optional) The longitude the status refers to.
|
||||
@param media (Optional) a media upload, such as an image or movie file.
|
||||
|
||||
@sa @ref authentication
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li If the @e source parameter is not supplied the source of the status will default to 'api'. When authenticated via a registered OAuth application, the application's registered name and URL will always override the source parameter.
|
||||
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
|
||||
to encode the latitude and longitude (see example response below <georss:point>).
|
||||
@li Data uploaded via the @e media parameter should be multipart/form-data encoded.
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl -u username:password http://example.com/api/statuses/update.xml -d status='Howdy!' -d lat='30.468' -d long='-94.743'
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<status>
|
||||
<text>Howdy!</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Tue Mar 30 23:28:05 +0000 2010</created_at>
|
||||
<in_reply_to_status_id/>
|
||||
<source>api</source>
|
||||
<id>26668724</id>
|
||||
<in_reply_to_user_id/>
|
||||
<in_reply_to_screen_name/>
|
||||
<geo xmlns:georss="http://www.georss.org/georss">
|
||||
<georss:point>30.468 -94.743</georss:point>
|
||||
</geo>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>25803</id>
|
||||
<name>Jed Sanders</name>
|
||||
<screen_name>jedsanders</screen_name>
|
||||
<location>Hoop and Holler, Texas</location>
|
||||
<description>I like to think of myself as America's Favorite.</description>
|
||||
<profile_image_url>http://avatar.example.com/25803-48-20080924200604.png</profile_image_url>
|
||||
<url>http://jedsanders.net</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>5</followers_count>
|
||||
<profile_background_color/>
|
||||
<profile_text_color/>
|
||||
<profile_link_color/>
|
||||
<profile_sidebar_fill_color/>
|
||||
<profile_sidebar_border_color/>
|
||||
<friends_count>2</friends_count>
|
||||
<created_at>Wed Sep 24 20:04:00 +0000 2008</created_at>
|
||||
<favourites_count>0</favourites_count>
|
||||
<utc_offset>0</utc_offset>
|
||||
<time_zone>UTC</time_zone>
|
||||
<profile_background_image_url/>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>70</statuses_count>
|
||||
<following>true</following>
|
||||
<notifications>true</notifications>
|
||||
</user>
|
||||
</status>
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the authenticating user's status (posts a notice).
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $status = null;
|
||||
var $in_reply_to_status_id = null;
|
||||
var $lat = null;
|
||||
var $lon = null;
|
||||
var $media_ids = array(); // file_id in the keys
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->status = $this->trimmed('status');
|
||||
$this->lat = $this->trimmed('lat');
|
||||
$this->lon = $this->trimmed('long');
|
||||
$matches = array();
|
||||
common_debug(get_called_class().': media_ids=='._ve($this->trimmed('media_ids')));
|
||||
if (preg_match_all('/\d+/', $this->trimmed('media_ids'), $matches) !== false) {
|
||||
foreach (array_unique($matches[0]) as $match) {
|
||||
try {
|
||||
$this->media_ids[$match] = File::getByID($match);
|
||||
} catch (EmptyPkeyValueException $e) {
|
||||
// got a zero from the client, at least Twidere does this on occasion
|
||||
} catch (NoResultException $e) {
|
||||
// File ID was not found. Do we abort and report to the client?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->in_reply_to_status_id
|
||||
= intval($this->trimmed('in_reply_to_status_id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
|
||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
|
||||
if (empty($this->status)) {
|
||||
// TRANS: Client error displayed when the parameter "status" is missing.
|
||||
$this->clientError(_('Client must provide a \'status\' parameter with a value.'));
|
||||
}
|
||||
|
||||
if (is_null($this->scoped)) {
|
||||
// TRANS: Client error displayed when updating a status for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
/* Do not call shortenLinks until the whole notice has been build */
|
||||
|
||||
// Check for commands
|
||||
|
||||
$inter = new CommandInterpreter();
|
||||
$cmd = $inter->handle_command($this->auth_user, $this->status);
|
||||
|
||||
if ($cmd) {
|
||||
if ($this->supported($cmd)) {
|
||||
$cmd->execute(new Channel());
|
||||
}
|
||||
|
||||
// Cmd not supported? Twitter just returns your latest status.
|
||||
// And, it returns your last status whether the cmd was successful
|
||||
// or not!
|
||||
|
||||
$this->notice = $this->auth_user->getCurrentNotice();
|
||||
} else {
|
||||
$reply_to = null;
|
||||
|
||||
if (!empty($this->in_reply_to_status_id)) {
|
||||
// Check whether notice actually exists
|
||||
|
||||
$reply = Notice::getKV($this->in_reply_to_status_id);
|
||||
|
||||
if ($reply) {
|
||||
$reply_to = $this->in_reply_to_status_id;
|
||||
} else {
|
||||
// TRANS: Client error displayed when replying to a non-existing notice.
|
||||
$this->clientError(_('Parent notice not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(array_keys($this->media_ids) as $media_id) {
|
||||
// FIXME: Validation on this... Worst case is that if someone sends bad media_ids then
|
||||
// we'll fill the notice with non-working links, so no real harm, done, but let's fix.
|
||||
// The File objects are in the array, so we could get URLs from them directly.
|
||||
$this->status .= ' ' . common_local_url('attachment', array('attachment' => $media_id));
|
||||
}
|
||||
|
||||
$upload = null;
|
||||
try {
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
$this->status .= ' ' . $upload->shortUrl();
|
||||
/* Do not call shortenLinks until the whole notice has been build */
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
// There was no uploaded media for us today.
|
||||
}
|
||||
|
||||
/* Do call shortenlinks here & check notice length since notice is about to be saved & sent */
|
||||
$status_shortened = $this->auth_user->shortenLinks($this->status);
|
||||
|
||||
if (Notice::contentTooLong($status_shortened)) {
|
||||
if ($upload instanceof MediaFile) {
|
||||
$upload->delete();
|
||||
}
|
||||
// TRANS: Client error displayed exceeding the maximum notice length.
|
||||
// TRANS: %d is the maximum lenth for a notice.
|
||||
$msg = _m('Maximum notice size is %d character, including attachment URL.',
|
||||
'Maximum notice size is %d characters, including attachment URL.',
|
||||
Notice::maxContent());
|
||||
/* Use HTTP 413 error code (Request Entity Too Large)
|
||||
* instead of basic 400 for better understanding
|
||||
*/
|
||||
$this->clientError(sprintf($msg, Notice::maxContent()), 413);
|
||||
}
|
||||
|
||||
|
||||
$content = html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$options = array('reply_to' => $reply_to);
|
||||
|
||||
if ($this->scoped->shareLocation()) {
|
||||
|
||||
$locOptions = Notice::locationOptions($this->lat,
|
||||
$this->lon,
|
||||
null,
|
||||
null,
|
||||
$this->scoped);
|
||||
|
||||
$options = array_merge($options, $locOptions);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->notice = Notice::saveNew(
|
||||
$this->scoped->id,
|
||||
$content,
|
||||
$this->source,
|
||||
$options
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
if (isset($upload)) {
|
||||
$upload->attachToNotice($this->notice);
|
||||
}
|
||||
}
|
||||
|
||||
$this->showNotice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the resulting notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->show_single_json_status($this->notice);
|
||||
} elseif ($this->format == 'atom') {
|
||||
$this->showSingleAtomStatus($this->notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this command supported when doing an update from the API?
|
||||
*
|
||||
* @param string $cmd the command to check for
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function supported($cmd)
|
||||
{
|
||||
static $cmdlist = array('SubCommand', 'UnsubCommand',
|
||||
'OnCommand', 'OffCommand', 'JoinCommand', 'LeaveCommand');
|
||||
|
||||
$supported = null;
|
||||
|
||||
if (Event::handle('CommandSupportedAPI', array($cmd, &$supported))) {
|
||||
$supported = $supported || in_array(get_class($cmd), $cmdlist);
|
||||
}
|
||||
|
||||
return $supported;
|
||||
}
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Base class for showing subscription information in the API
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class outputs a list of profiles as Twitter-style user and status objects.
|
||||
* It is used by the API methods /api/statuses/(friends|followers). To support the
|
||||
* social graph methods it also can output a simple list of IDs.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
abstract class ApiSubscriptionsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $profiles = null;
|
||||
var $tag = null;
|
||||
var $lite = null;
|
||||
var $ids_only = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->tag = $this->arg('tag');
|
||||
|
||||
// Note: Twitter no longer supports 'lite'
|
||||
$this->lite = $this->arg('lite');
|
||||
|
||||
$this->ids_only = $this->arg('ids_only');
|
||||
|
||||
// If called as a social graph method, show 5000 per page, otherwise 100
|
||||
|
||||
$this->count = isset($this->ids_only) ?
|
||||
5000 : (int)$this->arg('count', 100);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting a list of followers for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the profiles
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
$this->initDocument($this->format);
|
||||
|
||||
if (isset($this->ids_only)) {
|
||||
$this->showIds();
|
||||
} else {
|
||||
$this->showProfiles(isset($this->lite) ? false : true);
|
||||
}
|
||||
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profiles related to the type of subscriber/subscription action
|
||||
*
|
||||
* @return array Profiles
|
||||
*/
|
||||
abstract protected function getProfiles();
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest profile in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this action
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last profiles in the subscriptions list
|
||||
* There's also an indicator to show whether this action is being called
|
||||
* as /api/statuses/(friends|followers) or /api/(friends|followers)/ids
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
// Caching tags.
|
||||
isset($this->ids_only) ? 'IDs' : 'Profiles',
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the profiles as Twitter-style useres and statuses
|
||||
*
|
||||
* @param boolean $include_statuses Whether to include the latest status
|
||||
* with each user. Default true.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showProfiles($include_statuses = true)
|
||||
{
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->elementStart('users', array('type' => 'array',
|
||||
'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
|
||||
foreach ($this->profiles as $profile) {
|
||||
$this->showProfile(
|
||||
$profile,
|
||||
$this->format,
|
||||
null,
|
||||
$include_statuses
|
||||
);
|
||||
}
|
||||
$this->elementEnd('users');
|
||||
break;
|
||||
case 'json':
|
||||
$arrays = array();
|
||||
foreach ($this->profiles as $profile) {
|
||||
$arrays[] = $this->twitterUserArray(
|
||||
$profile,
|
||||
$include_statuses
|
||||
);
|
||||
}
|
||||
print json_encode($arrays);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when requesting profiles of followers in an unsupported format.
|
||||
$this->clientError(_('Unsupported format.'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the IDs of the profiles only. 5000 per page. To support
|
||||
* the 'social graph' methods: /api/(friends|followers)/ids
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showIds()
|
||||
{
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->elementStart('ids');
|
||||
foreach ($this->profiles as $profile) {
|
||||
$this->element('id', null, $profile->id);
|
||||
}
|
||||
$this->elementEnd('ids');
|
||||
break;
|
||||
case 'json':
|
||||
$ids = array();
|
||||
foreach ($this->profiles as $profile) {
|
||||
$ids[] = (int)$profile->id;
|
||||
}
|
||||
print json_encode($ids);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when requesting IDs of followers in an unsupported format.
|
||||
$this->clientError(_('Unsupported format.'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,344 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the friends timeline
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page friendstimeline statuses/friends_timeline
|
||||
|
||||
@section Description
|
||||
Returns the 20 most recent statuses posted by the authenticating
|
||||
user and that user's friends. This is the equivalent of "You and
|
||||
friends" page in the web interface.
|
||||
|
||||
@par URL patterns
|
||||
@li /api/statuses/friends_timeline.:format
|
||||
@li /api/statuses/friends_timeline/:id.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json, rss, atom
|
||||
|
||||
@par ID (:id)
|
||||
username, user id
|
||||
|
||||
@par HTTP Method(s)
|
||||
GET
|
||||
|
||||
@par Requires Authentication
|
||||
Sometimes (see: @ref authentication)
|
||||
|
||||
@param user_id (Optional) Specifies a user by ID
|
||||
@param screen_name (Optional) Specifies a user by screename (nickname)
|
||||
@param since_id (Optional) Returns only statuses with an ID greater
|
||||
than (that is, more recent than) the specified ID.
|
||||
@param max_id (Optional) Returns only statuses with an ID less than
|
||||
(that is, older than) or equal to the specified ID.
|
||||
@param count (Optional) Specifies the number of statuses to retrieve.
|
||||
@param page (Optional) Specifies the page of results to retrieve.
|
||||
|
||||
@sa @ref authentication
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
|
||||
to encode the latitude and longitude (see example response below <georss:point>).
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0"?>
|
||||
<statuses type="array">
|
||||
<status>
|
||||
<text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
|
||||
<in_reply_to_status_id/>
|
||||
<source><a href="http://somesourcecode.net/microblog/">mbpidgin</a></source>
|
||||
<id>26674201</id>
|
||||
<in_reply_to_user_id/>
|
||||
<in_reply_to_screen_name/>
|
||||
<geo/>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>246</id>
|
||||
<name>Mark</name>
|
||||
<screen_name>lambic</screen_name>
|
||||
<location>Montreal, Canada</location>
|
||||
<description>Geek</description>
|
||||
<profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
|
||||
<url>http://lambic.co.uk</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>73</followers_count>
|
||||
<profile_background_color>#F0F2F5</profile_background_color>
|
||||
<profile_text_color/>
|
||||
<profile_link_color>#002E6E</profile_link_color>
|
||||
<profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
|
||||
<profile_sidebar_border_color/>
|
||||
<friends_count>58</friends_count>
|
||||
<created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
|
||||
<favourites_count>2</favourites_count>
|
||||
<utc_offset>-14400</utc_offset>
|
||||
<time_zone>US/Eastern</time_zone>
|
||||
<profile_background_image_url/>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>933</statuses_count>
|
||||
<following>false</following>
|
||||
<notifications>false</notifications>
|
||||
</user>
|
||||
</status>
|
||||
</statuses>
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the target user.
|
||||
* This is the equivalent of 'You and friends' page accessed via Web.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineFriendsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Title of API timeline for a user and friends.
|
||||
// TRANS: %s is a username.
|
||||
$title = sprintf(_("%s and friends"), $this->target->nickname);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:FriendsTimeline:" . $this->target->id;
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
|
||||
_('Updates from %1$s and friends on %2$s!'),
|
||||
$this->target->nickname,
|
||||
$sitename
|
||||
);
|
||||
|
||||
$logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$link = common_local_url('all',
|
||||
array('nickname' => $this->target->nickname));
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($logo);
|
||||
$atom->setUpdated('now');
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user, $title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a group's notices
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted to the group specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed requesting most recent notices to a group for a non-existing group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
// We'll pull common formatting out of this for other formats
|
||||
$atom = new AtomGroupNoticeFeed($this->group, $this->auth_user);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
$link = common_local_url('showgroup',
|
||||
array('nickname' => $this->group->nickname));
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$atom->title,
|
||||
$this->group->homeUrl(),
|
||||
$atom->subtitle,
|
||||
null,
|
||||
$atom->logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($atom->title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when trying to handle an unknown API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$notice = $this->group->getNotices(
|
||||
($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, group ID and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the home timeline
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the target user.
|
||||
* This is the equivalent of 'You and friends' page accessed via Web.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineHomeAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting most recent dents by user and friends for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Timeline title for user and friends. %s is a user nickname.
|
||||
$title = sprintf(_("%s and friends"), $this->target->nickname);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:HomeTimeline:" . $this->target->id;
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
|
||||
_('Updates from %1$s and friends on %2$s!'),
|
||||
$this->target->nickname, $sitename
|
||||
);
|
||||
|
||||
$logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$link = common_local_url('all',
|
||||
array('nickname' => $this->target->nickname));
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($logo);
|
||||
$atom->setUpdated('now');
|
||||
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a list's notices
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/atomlistnoticefeed.php';
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted to the list specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineListAction extends ApiPrivateAuthAction
|
||||
{
|
||||
|
||||
var $list = null;
|
||||
var $notices = array();
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
var $cursor = -1;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->list)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
$this->getNotices();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
// We'll pull common formatting out of this for other formats
|
||||
$atom = new AtomListNoticeFeed($this->list, $this->auth_user);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->elementStart('statuses_list',
|
||||
array('xmlns:statusnet' => 'http://status.net/schema/api/1/'));
|
||||
$this->elementStart('statuses', array('type' => 'array'));
|
||||
|
||||
foreach ($this->notices as $n) {
|
||||
$twitter_status = $this->twitterStatusArray($n);
|
||||
$this->showTwitterXmlStatus($twitter_status);
|
||||
}
|
||||
|
||||
$this->elementEnd('statuses');
|
||||
$this->element('next_cursor', null, $this->next_cursor);
|
||||
$this->element('previous_cursor', null, $this->prev_cursor);
|
||||
$this->elementEnd('statuses_list');
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$atom->title,
|
||||
$this->list->getUri(),
|
||||
$atom->subtitle,
|
||||
null,
|
||||
$atom->logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
try {
|
||||
$atom->setId($self);
|
||||
$atom->setSelfLink($self);
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
} catch (Atom10FeedException $e) {
|
||||
// TRANS: Server error displayed whe trying to get a timeline fails.
|
||||
// TRANS: %s is the error message.
|
||||
$this->serverError(sprintf(_('Could not generate feed for list - %s'), $e->getMessage()));
|
||||
}
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
|
||||
$statuses = array();
|
||||
foreach ($this->notices as $n) {
|
||||
$twitter_status = $this->twitterStatusArray($n);
|
||||
array_push($statuses, $twitter_status);
|
||||
}
|
||||
|
||||
$statuses_list = array('statuses' => $statuses,
|
||||
'next_cursor' => $this->next_cusror,
|
||||
'next_cursor_str' => strval($this->next_cusror),
|
||||
'previous_cursor' => $this->prev_cusror,
|
||||
'previous_cursor_str' => strval($this->prev_cusror)
|
||||
);
|
||||
$this->showJsonObjects($statuses_list);
|
||||
|
||||
$this->initDocument('json');
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$fn = array($this->list, 'getNotices');
|
||||
list($this->notices, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
if (!$this->notices) {
|
||||
$this->notices = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, list ID and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->list->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show notices mentioning a user (@nickname)
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent (default 20) mentions (status containing @nickname)
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineMentionsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting most recent mentions for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(
|
||||
// TRANS: Title for timeline of most recent mentions of a user.
|
||||
// TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
|
||||
_('%1$s / Updates mentioning %2$s'),
|
||||
$sitename, $this->target->nickname
|
||||
);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:Mentions:" . $this->target->id;
|
||||
|
||||
$logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$link = common_local_url('replies',
|
||||
array('nickname' => $this->target->nickname));
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Subtitle for timeline of most recent mentions of a user.
|
||||
// TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname,
|
||||
// TRANS: %3$s is a user's full name.
|
||||
_('%1$s updates that reply to updates from %3$s / %2$s.'),
|
||||
$sitename, $this->target->nickname, $this->target->getBestName()
|
||||
);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($logo);
|
||||
$atom->setUpdated('now');
|
||||
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = new ReplyNoticeStream($this->target->id, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiTimelineNetworkPublicAction extends ApiTimelinePublicAction
|
||||
{
|
||||
function title()
|
||||
{
|
||||
return sprintf(_("%s network public timeline"), common_config('site', 'name'));
|
||||
}
|
||||
|
||||
protected function getStream()
|
||||
{
|
||||
if (!$this->scoped instanceof Profile && common_config('public', 'localonly')) {
|
||||
$this->clientError(_('Network wide public feed is not permitted without authorization'), 403);
|
||||
}
|
||||
return new NetworkPublicNoticeStream($this->scoped);
|
||||
}
|
||||
}
|
||||
@@ -1,335 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the public timeline
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by everybody
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page publictimeline statuses/public_timeline
|
||||
|
||||
@section Description
|
||||
Returns the 20 most recent notices from users throughout the system who have
|
||||
uploaded their own avatars. Depending on configuration, it may or may not
|
||||
not include notices from automatic posting services.
|
||||
|
||||
@par URL patterns
|
||||
@li /api/statuses/public_timeline.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json, rss, atom
|
||||
|
||||
@par HTTP Method(s)
|
||||
GET
|
||||
|
||||
@par Requires Authentication
|
||||
No
|
||||
|
||||
@param since_id (Optional) Returns only statuses with an ID greater
|
||||
than (that is, more recent than) the specified ID.
|
||||
@param max_id (Optional) Returns only statuses with an ID less than
|
||||
(that is, older than) or equal to the specified ID.
|
||||
@param count (Optional) Specifies the number of statuses to retrieve.
|
||||
@param page (Optional) Specifies the page of results to retrieve.
|
||||
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
|
||||
to encode the latitude and longitude (see example response below <georss:point>).
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<statuses type="array">
|
||||
<status>
|
||||
<text>@skwashd oh, commbank reenabled me super quick both times. but disconcerting when you don't expect it though</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Sat Apr 17 00:49:12 +0000 2010</created_at>
|
||||
<in_reply_to_status_id>28838393</in_reply_to_status_id>
|
||||
<source>xmpp</source>
|
||||
<id>28838456</id>
|
||||
<in_reply_to_user_id>39303</in_reply_to_user_id>
|
||||
<in_reply_to_screen_name>skwashd</in_reply_to_screen_name>
|
||||
<geo></geo>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>44517</id>
|
||||
<name>joshua may</name>
|
||||
<screen_name>notjosh</screen_name>
|
||||
<location></location>
|
||||
<description></description>
|
||||
<profile_image_url>http://avatar.identi.ca/44517-48-20090321004106.jpeg</profile_image_url>
|
||||
<url></url>
|
||||
<protected>false</protected>
|
||||
<followers_count>17</followers_count>
|
||||
<profile_background_color></profile_background_color>
|
||||
<profile_text_color></profile_text_color>
|
||||
<profile_link_color></profile_link_color>
|
||||
<profile_sidebar_fill_color></profile_sidebar_fill_color>
|
||||
<profile_sidebar_border_color></profile_sidebar_border_color>
|
||||
<friends_count>20</friends_count>
|
||||
<created_at>Sat Mar 21 00:40:25 +0000 2009</created_at>
|
||||
<favourites_count>0</favourites_count>
|
||||
<utc_offset>0</utc_offset>
|
||||
<time_zone>UTC</time_zone>
|
||||
<profile_background_image_url></profile_background_image_url>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>100</statuses_count>
|
||||
<following>false</following>
|
||||
<notifications>false</notifications>
|
||||
</user>
|
||||
</status>
|
||||
[....]
|
||||
</statuses>
|
||||
@endverbatim
|
||||
*/
|
||||
class ApiTimelinePublicAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Title for site timeline. %s is the GNU social sitename.
|
||||
return sprintf(_("%s public timeline"), common_config('site', 'name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$nonapi_action = substr($this->action, strlen('apitimeline')); // Just so we don't need to set this explicitly
|
||||
|
||||
$sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
|
||||
$title = $this->title();
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:" . ucfirst($nonapi_action) . 'Timeline'; // Public or Networkpublic probably
|
||||
$link = common_local_url($nonapi_action);
|
||||
$self = $this->getSelfUri();
|
||||
// TRANS: Subtitle for site timeline. %s is the GNU social sitename.
|
||||
$subtitle = sprintf(_("%s updates from everyone!"), common_config('site', 'name'));
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$sitelogo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($sitelogo);
|
||||
$atom->setUpdated('now');
|
||||
$atom->addLink(common_local_url($nonapi_action));
|
||||
$atom->setSelfLink($self);
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = $this->getStream();
|
||||
|
||||
$notice = $stream->getNotices(($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
$notices = $notice->fetchAll();
|
||||
|
||||
NoticeList::prefill($notices);
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
protected function getStream()
|
||||
{
|
||||
return new PublicNoticeStream($this->scoped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the latest notices for a given tag
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 20 most recent notices tagged by a given tag
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineTagAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->tag = $this->arg('tag');
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
$sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
|
||||
// TRANS: Title for timeline with lastest notices with a given tag.
|
||||
// TRANS: %s is the tag.
|
||||
$title = sprintf(_("Notices tagged with %s"), $this->tag);
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Subtitle for timeline with lastest notices with a given tag.
|
||||
// TRANS: %1$s is the tag, $2$s is the StatusNet sitename.
|
||||
_('Updates tagged with %1$s on %2$s!'),
|
||||
$this->tag,
|
||||
$sitename
|
||||
);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:TagTimeline:".$this->tag;
|
||||
|
||||
$link = common_local_url(
|
||||
'tag',
|
||||
array('tag' => $this->tag)
|
||||
);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$sitelogo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($sitelogo);
|
||||
$atom->setUpdated('now');
|
||||
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notice = Notice_tag::getStream($this->tag)->getNotices(($this->page - 1) * $this->count,
|
||||
$this->count + 1,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
return $notice->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->tag,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,409 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a user's timeline
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the authenticating
|
||||
* user. Another user's timeline can be requested via the id parameter. This
|
||||
* is the API equivalent of the user profile web page.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
{
|
||||
public $notices = null;
|
||||
|
||||
public $next_id = null;
|
||||
|
||||
/**
|
||||
* We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
public function isReadOnly($args)
|
||||
{
|
||||
return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
public function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
public function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->scoped),
|
||||
common_language(),
|
||||
$this->target->getID(),
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
* @throws AuthorizationException
|
||||
* @throws ClientException
|
||||
*/
|
||||
protected function prepare(array $args = [])
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed requesting most recent notices for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (!$this->target->isLocal()) {
|
||||
$this->serverError(_('Remote user timelines are not available here yet.'), 501);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
public function getNotices()
|
||||
{
|
||||
$notices = [];
|
||||
|
||||
$notice = $this->target->getNotices(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count + 1,
|
||||
$this->since_id,
|
||||
$this->max_id,
|
||||
$this->scoped
|
||||
);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
if (count($notices) < $this->count) {
|
||||
$notices[] = clone($notice);
|
||||
} else {
|
||||
$this->next_id = $notice->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
* @throws ClientException
|
||||
* @throws ServerException
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if ($this->isPost()) {
|
||||
$this->handlePost();
|
||||
} else {
|
||||
$this->showTimeline();
|
||||
}
|
||||
}
|
||||
|
||||
public function handlePost()
|
||||
{
|
||||
if (!$this->scoped instanceof Profile ||
|
||||
!$this->target->sameAs($this->scoped)) {
|
||||
// TRANS: Client error displayed trying to add a notice to another user's timeline.
|
||||
$this->clientError(_('Only the user can add to their own timeline.'), 403);
|
||||
}
|
||||
|
||||
// Only handle posts for Atom
|
||||
if ($this->format != 'atom') {
|
||||
// TRANS: Client error displayed when using another format than AtomPub.
|
||||
$this->clientError(_('Only accept AtomPub for Atom feeds.'));
|
||||
}
|
||||
|
||||
$xml = trim(file_get_contents('php://input'));
|
||||
if (empty($xml)) {
|
||||
// TRANS: Client error displayed attempting to post an empty API notice.
|
||||
$this->clientError(_('Atom post must not be empty.'));
|
||||
}
|
||||
|
||||
$old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
|
||||
$dom = new DOMDocument();
|
||||
$ok = $dom->loadXML($xml);
|
||||
error_reporting($old);
|
||||
if (!$ok) {
|
||||
// TRANS: Client error displayed attempting to post an API that is not well-formed XML.
|
||||
$this->clientError(_('Atom post must be well-formed XML.'));
|
||||
}
|
||||
|
||||
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
|
||||
$dom->documentElement->localName != 'entry') {
|
||||
// TRANS: Client error displayed when not using an Atom entry.
|
||||
$this->clientError(_('Atom post must be an Atom entry.'));
|
||||
}
|
||||
|
||||
$activity = new Activity($dom->documentElement);
|
||||
|
||||
common_debug('AtomPub: Ignoring right now, but this POST was made to collection: ' . $activity->id);
|
||||
|
||||
// Reset activity data so we can handle it in the same functions as with OStatus
|
||||
// because we don't let clients set their own UUIDs... Not sure what AtomPub thinks
|
||||
// about that though.
|
||||
$activity->id = null;
|
||||
$activity->actor = null; // not used anyway, we use $this->target
|
||||
$activity->objects[0]->id = null;
|
||||
|
||||
$stored = null;
|
||||
if (Event::handle('StartAtomPubNewActivity', array($activity, $this->target, &$stored))) {
|
||||
// TRANS: Client error displayed when not using the POST verb. Do not translate POST.
|
||||
throw new ClientException(_('Could not handle this Atom Activity.'));
|
||||
}
|
||||
if (!$stored instanceof Notice) {
|
||||
throw new ServerException('Server did not create a Notice object from handled AtomPub activity.');
|
||||
}
|
||||
Event::handle('EndAtomPubNewActivity', array($activity, $this->target, $stored));
|
||||
|
||||
header('HTTP/1.1 201 Created');
|
||||
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $stored->getID(),
|
||||
'format' => 'atom')));
|
||||
$this->showSingleAtomStatus($stored);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
* @throws ClientException
|
||||
* @throws ServerException
|
||||
* @throws UserNoProfileException
|
||||
*/
|
||||
public function showTimeline()
|
||||
{
|
||||
// We'll use the shared params from the Atom stub
|
||||
// for other feed types.
|
||||
$atom = new AtomUserNoticeFeed($this->target->getUser(), $this->scoped);
|
||||
|
||||
$link = common_local_url(
|
||||
'showstream',
|
||||
array('nickname' => $this->target->getNickname())
|
||||
);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
// FriendFeed's SUP protocol
|
||||
// Also added RSS and Atom feeds
|
||||
|
||||
$suplink = common_local_url('sup', null, null, $this->target->getID());
|
||||
header('X-SUP-ID: ' . $suplink);
|
||||
|
||||
|
||||
// paging links
|
||||
$nextUrl = !empty($this->next_id)
|
||||
? common_local_url(
|
||||
'ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->getID()),
|
||||
array('max_id' => $this->next_id)
|
||||
)
|
||||
: null;
|
||||
|
||||
$prevExtra = [];
|
||||
if (!empty($this->notices)) {
|
||||
assert($this->notices[0] instanceof Notice);
|
||||
$prevExtra['since_id'] = $this->notices[0]->id;
|
||||
}
|
||||
|
||||
$prevUrl = common_local_url(
|
||||
'ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->getID()),
|
||||
$prevExtra
|
||||
);
|
||||
$firstUrl = common_local_url(
|
||||
'ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->getID())
|
||||
);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$atom->title,
|
||||
$link,
|
||||
$atom->subtitle,
|
||||
$suplink,
|
||||
$atom->logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom->setId($self);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
// Add navigation links: next, prev, first
|
||||
// Note: we use IDs rather than pages for navigation; page boundaries
|
||||
// change too quickly!
|
||||
|
||||
if (!empty($this->next_id)) {
|
||||
$atom->addLink(
|
||||
$nextUrl,
|
||||
array('rel' => 'next',
|
||||
'type' => 'application/atom+xml')
|
||||
);
|
||||
}
|
||||
|
||||
if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
|
||||
$atom->addLink(
|
||||
$prevUrl,
|
||||
array('rel' => 'prev',
|
||||
'type' => 'application/atom+xml')
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
|
||||
$atom->addLink(
|
||||
$firstUrl,
|
||||
array('rel' => 'first',
|
||||
'type' => 'application/atom+xml')
|
||||
);
|
||||
}
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->scoped);
|
||||
$doc->setTitle($atom->title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
|
||||
if (!empty($this->next_id)) {
|
||||
$doc->addLink(
|
||||
$nextUrl,
|
||||
array('rel' => 'next',
|
||||
'type' => ActivityStreamJSONDocument::CONTENT_TYPE)
|
||||
);
|
||||
}
|
||||
|
||||
if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
|
||||
$doc->addLink(
|
||||
$prevUrl,
|
||||
array('rel' => 'prev',
|
||||
'type' => ActivityStreamJSONDocument::CONTENT_TYPE)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
|
||||
$doc->addLink(
|
||||
$firstUrl,
|
||||
array('rel' => 'first',
|
||||
'type' => ActivityStreamJSONDocument::CONTENT_TYPE)
|
||||
);
|
||||
}
|
||||
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List of replies
|
||||
*
|
||||
* 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 Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top ten queries that are currently trending
|
||||
*
|
||||
* @category Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see ApiAction
|
||||
*/
|
||||
class ApiTrendsAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $callback;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if user doesn't exist
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTrends();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the trends
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTrends()
|
||||
{
|
||||
// TRANS: Server error for unfinished API method showTrends.
|
||||
$this->serverError(_('API method under construction.'), 501);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a user's followers (subscribers)
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Ouputs the authenticating user's followers (subscribers), each with
|
||||
* current Twitter-style status inline. They are ordered by the order
|
||||
* in which they subscribed to the user, 100 at a time.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiUserFollowersAction extends ApiSubscriptionsAction
|
||||
{
|
||||
/**
|
||||
* Get the user's subscribers (followers) as an array of profiles
|
||||
*
|
||||
* @return array Profiles
|
||||
*/
|
||||
protected function getProfiles()
|
||||
{
|
||||
$offset = ($this->page - 1) * $this->count;
|
||||
$limit = $this->count + 1;
|
||||
|
||||
$subs = null;
|
||||
|
||||
if (isset($this->tag)) {
|
||||
$subs = $this->target->getTaggedSubscribers(
|
||||
$this->tag, $offset, $limit
|
||||
);
|
||||
} else {
|
||||
$subs = $this->target->getSubscribers(
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
|
||||
$profiles = array();
|
||||
|
||||
while ($subs->fetch()) {
|
||||
$profiles[] = clone($subs);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a user's friends (subscriptions)
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Ouputs the authenticating user's friends (subscriptions), each with
|
||||
* current Twitter-style status inline. They are ordered by the date
|
||||
* in which the user subscribed to them, 100 at a time.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiUserFriendsAction extends ApiSubscriptionsAction
|
||||
{
|
||||
/**
|
||||
* Get the user's subscriptions (friends) as an array of profiles
|
||||
*
|
||||
* @return array Profiles
|
||||
*/
|
||||
protected function getProfiles()
|
||||
{
|
||||
$offset = ($this->page - 1) * $this->count;
|
||||
$limit = $this->count + 1;
|
||||
|
||||
$subs = null;
|
||||
|
||||
if (isset($this->tag)) {
|
||||
$subs = $this->target->getTaggedSubscriptions(
|
||||
$this->tag, $offset, $limit
|
||||
);
|
||||
} else {
|
||||
$subs = $this->target->getSubscribed(
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
|
||||
$profiles = array();
|
||||
|
||||
while ($subs->fetch()) {
|
||||
$profiles[] = clone($subs);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Return a user's avatar image
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Brion Vibber <brion@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouputs avatar URL for a user, specified by screen name.
|
||||
* Unlike most API endpoints, this returns an HTTP redirect rather than direct data.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Brion Vibber <brion@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiUserProfileImageAction extends ApiPrivateAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
$user = User::getKV('nickname', $this->arg('screen_name'));
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed when requesting user information for a non-existing user.
|
||||
$this->clientError(_('User not found.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
$this->size = $this->arg('size');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$size = $this->avatarSize();
|
||||
$url = $this->target->avatarUrl($size);
|
||||
|
||||
// We don't actually output JSON or XML data -- redirect!
|
||||
common_redirect($url, 302);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate pixel size for an avatar based on the request...
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function avatarSize()
|
||||
{
|
||||
switch ($this->size) {
|
||||
case 'mini':
|
||||
return AVATAR_MINI_SIZE; // 24x24
|
||||
case 'bigger':
|
||||
return AVATAR_PROFILE_SIZE; // Twitter does 73x73, but we do 96x96
|
||||
case 'normal': // fall through
|
||||
default:
|
||||
return AVATAR_STREAM_SIZE; // 48x48
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a user's profile information
|
||||
*
|
||||
* 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 API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouputs information for a user, specified by ID or screen name.
|
||||
* The user's most recent status will be returned inline.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiUserShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$email = $this->arg('email');
|
||||
|
||||
// XXX: email field deprecated in Twitter's API
|
||||
|
||||
if (!empty($email)) {
|
||||
$user = User::getKV('email', $email);
|
||||
} else {
|
||||
$user = $this->getTargetUser($this->arg('id'));
|
||||
}
|
||||
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed when requesting user information for a non-existing user.
|
||||
$this->clientError(_('User not found.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->target, true);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Leave a group
|
||||
*
|
||||
* 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 Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a group
|
||||
*
|
||||
* This is the action for leaving a group. It works more or less like the subscribe action
|
||||
* for users.
|
||||
*
|
||||
* @category Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApprovegroupAction extends Action
|
||||
{
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
function prepare(array $args = array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
// TRANS: Client error displayed when trying to leave a group while not logged in.
|
||||
$this->clientError(_('You must be logged in to leave a group.'));
|
||||
}
|
||||
|
||||
$nickname_arg = $this->trimmed('nickname');
|
||||
$id = intval($this->arg('id'));
|
||||
if ($id) {
|
||||
$this->group = User_group::getKV('id', $id);
|
||||
} else if ($nickname_arg) {
|
||||
$nickname = common_canonical_nickname($nickname_arg);
|
||||
|
||||
// Permanent redirect on non-canonical nickname
|
||||
|
||||
if ($nickname_arg != $nickname) {
|
||||
$args = array('nickname' => $nickname);
|
||||
common_redirect(common_local_url('leavegroup', $args), 301);
|
||||
}
|
||||
|
||||
$local = Local_group::getKV('nickname', $nickname);
|
||||
|
||||
if (!$local) {
|
||||
// TRANS: Client error displayed when trying to leave a non-local group.
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
}
|
||||
|
||||
$this->group = User_group::getKV('id', $local->group_id);
|
||||
} else {
|
||||
// TRANS: Client error displayed when trying to leave a group without providing a group name or group ID.
|
||||
$this->clientError(_('No nickname or ID.'), 404);
|
||||
}
|
||||
|
||||
if (!$this->group) {
|
||||
// TRANS: Client error displayed when trying to leave a non-existing group.
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
if (empty($cur)) {
|
||||
// TRANS: Client error displayed trying to approve group membership while not logged in.
|
||||
$this->clientError(_('Must be logged in.'), 403);
|
||||
}
|
||||
if ($this->arg('profile_id')) {
|
||||
if ($cur->isAdmin($this->group)) {
|
||||
$this->profile = Profile::getKV('id', $this->arg('profile_id'));
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to approve group membership while not a group administrator.
|
||||
$this->clientError(_('Only group admin can approve or cancel join requests.'), 403);
|
||||
}
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to approve group membership without specifying a profile to approve.
|
||||
$this->clientError(_('Must specify a profile.'));
|
||||
}
|
||||
|
||||
$this->request = Group_join_queue::pkeyGet(array('profile_id' => $this->profile->id,
|
||||
'group_id' => $this->group->id));
|
||||
|
||||
if (empty($this->request)) {
|
||||
// TRANS: Client error displayed trying to approve group membership for a non-existing request.
|
||||
// TRANS: %s is a nickname.
|
||||
$this->clientError(sprintf(_('%s is not in the moderation queue for this group.'), $this->profile->nickname), 403);
|
||||
}
|
||||
|
||||
$this->approve = (bool)$this->arg('approve');
|
||||
$this->cancel = (bool)$this->arg('cancel');
|
||||
if (!$this->approve && !$this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny group membership.
|
||||
$this->clientError(_('Internal error: received neither cancel nor abort.'));
|
||||
}
|
||||
if ($this->approve && $this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny group membership.
|
||||
$this->clientError(_('Internal error: received both cancel and abort.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* On POST, add the current user to the group
|
||||
*
|
||||
* @param array $args unused
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
try {
|
||||
if ($this->approve) {
|
||||
$this->request->complete();
|
||||
} elseif ($this->cancel) {
|
||||
$this->request->abort();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_ERR, "Exception canceling group sub: " . $e->getMessage());
|
||||
// TRANS: Server error displayed when cancelling a queued group join request fails.
|
||||
// TRANS: %1$s is the leaving user's nickname, $2$s is the group nickname for which the leave failed.
|
||||
$this->serverError(sprintf(_('Could not cancel request for user %1$s to join group %2$s.'),
|
||||
$this->profile->nickname, $this->group->nickname));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title for leave group page after group join request is approved/disapproved.
|
||||
// TRANS: %1$s is the user nickname, %2$s is the group nickname.
|
||||
$this->element('title', null, sprintf(_m('TITLE','%1$s\'s request for %2$s'),
|
||||
$this->profile->nickname,
|
||||
$this->group->nickname));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
if ($this->approve) {
|
||||
// TRANS: Message on page for group admin after approving a join request.
|
||||
$this->element('p', 'success', _('Join request approved.'));
|
||||
} elseif ($this->cancel) {
|
||||
// TRANS: Message on page for group admin after rejecting a join request.
|
||||
$this->element('p', 'success', _('Join request canceled.'));
|
||||
}
|
||||
$this->elementEnd('body');
|
||||
$this->endHTML();
|
||||
} else {
|
||||
common_redirect(common_local_url('groupmembers', array('nickname' => $this->group->nickname)), 303);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user