forked from GNUsocial/gnu-social
Compare commits
762 Commits
v1.2.0beta
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
bdd55f611f | ||
|
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 | ||
|
d705bcbd98 | ||
|
f0f5ecb756 | ||
|
c0342b1482 | ||
|
d1fc7c0774 | ||
|
46be9b76ef | ||
|
6c8d2e159e | ||
|
db9bb6b5a1 | ||
|
5ea0d74a57 | ||
|
30a1a460b7 | ||
|
5eb61c17d4 | ||
|
0a4eeb89da | ||
|
11dc170ead | ||
|
98c0c1ed53 | ||
|
83a05724b8 | ||
|
44653d339d | ||
|
f2705180e0 | ||
|
306d80de94 | ||
|
2740ff8c4c | ||
|
74ad4038ac | ||
|
3f8593268e | ||
|
8ea83aac48 | ||
|
81d65afb28 | ||
|
c93547b080 | ||
|
54f75683c7 | ||
|
abfd691fda | ||
|
20c73f0596 | ||
|
b224d93098 | ||
|
719bf065ca | ||
|
a1041a53f7 | ||
|
711badb6b4 | ||
|
1e4063254b | ||
|
b8352e912f | ||
|
69a1d77480 | ||
|
54d7a7cccd | ||
|
c7afe2f86c | ||
|
5f4e3fe0eb | ||
|
fb95af1cf5 | ||
|
7b73d267d5 | ||
|
08b6cfde66 | ||
|
2110c20ecc | ||
|
9f51692f26 | ||
|
02c67fd114 | ||
|
b6be1a3659 | ||
|
00b4a084ad | ||
|
061e7891e9 | ||
|
a1af5562de | ||
|
df84ccd916 | ||
|
2f118fde9e | ||
|
46f98b3142 | ||
|
72ee098e0b | ||
|
43df2d201c | ||
|
691df04103 | ||
|
ab24f59660 | ||
|
3886db64bc | ||
|
e7a875755d | ||
|
7cf4e1bb09 | ||
|
eaea9d48c5 | ||
|
2e9fa8f4b7 | ||
|
d7d63e1464 | ||
|
bb175f3d4e | ||
|
4ca32628f7 | ||
|
6b4beb90e1 | ||
|
d7adc4e13f | ||
|
c13b935201 | ||
|
18fc39d2cf | ||
|
c083a8bcc2 | ||
|
e8783d46d0 | ||
|
d9a42550ff | ||
|
ceae66a30f | ||
|
031a491abd | ||
|
1536d3ef29 | ||
|
c03ed457a6 | ||
|
d2e6519bad | ||
|
688fa4839c | ||
|
fe411e8138 | ||
|
515682c0cd | ||
|
b17e0b4169 | ||
|
daa5f87fd4 | ||
|
d75b5d2f4a | ||
|
f6dbf66983 | ||
|
6cf674f8f8 | ||
|
7845a09b34 | ||
|
e4d432295d | ||
|
339204f1ee | ||
|
a4e679a118 | ||
|
195296846e | ||
|
7967db6ff5 | ||
|
c4f962a7d0 | ||
|
bc030da320 | ||
|
9cc7df51d6 | ||
|
bf7f17474d | ||
|
8a07edec5f | ||
|
0042971d74 | ||
|
6b5450b7e6 | ||
|
5dcc98d1c6 | ||
|
fc4aa470b2 | ||
|
586fb5a517 | ||
|
e186ad57d0 | ||
|
e6667db0cd | ||
|
e0887220b0 | ||
|
3290227b50 | ||
|
a59c439b46 | ||
|
7b6c887d76 | ||
|
25eb06ac46 | ||
|
0df8531834 | ||
|
496ab8c920 | ||
|
986030060b | ||
|
2d20656e22 | ||
|
98ebe1f63b | ||
|
1d529c021a | ||
|
f89c052cf8 | ||
|
38f2ecefac | ||
|
8305641b20 | ||
|
e473937cb9 | ||
|
8c9efff1ac | ||
|
37f8d3bef2 | ||
|
d1ba0dddec | ||
|
4a8f330ed2 | ||
|
63ab20d20b | ||
|
9a39ebe66f | ||
|
ddc3cecfc0 | ||
|
45479c90a3 | ||
|
b3c3af1ef6 | ||
|
2b43d484eb | ||
|
9688a55d56 | ||
|
e8e487187e | ||
|
4211206e3b | ||
|
ffe14fe5f3 | ||
|
c285f80b18 | ||
|
1e1543dd72 | ||
|
9c0c8a19dd | ||
|
ec98fd0c43 | ||
|
67a9c0415c | ||
|
a1ea335140 | ||
|
69bb81556f | ||
|
0b9a2fdf3a | ||
|
3b5fabbe97 | ||
|
fdd3d63098 | ||
|
5af96d3ec7 | ||
|
250221ff7f | ||
|
ec504ec4df | ||
|
96ce758c05 | ||
|
a45d9471ed | ||
|
a6e33bdd6a | ||
|
10f17efc4f | ||
|
d9fbc17f77 | ||
|
50f9f23ff1 | ||
|
34bd4e6441 | ||
|
0b75eaed92 | ||
|
e615032331 | ||
|
de8aed6a28 | ||
|
d61375cb7f | ||
|
4c8a8848ed | ||
|
00cbc852b0 | ||
|
8dd06cd8d8 | ||
|
20801a32f7 | ||
|
090f4a9474 | ||
|
0ef483fb4a | ||
|
945920f24d | ||
|
6938d26524 | ||
|
dea9f43d85 | ||
|
90e93b9656 | ||
|
586aaa596e | ||
|
457d32e273 | ||
|
dd8e17a387 | ||
|
93524c4be3 | ||
|
924bcd93e5 | ||
|
aa004d03aa | ||
|
7785219234 | ||
|
56e2b0007c | ||
|
a75b1df627 | ||
|
e3cafc011e | ||
|
3b363d626d | ||
|
d564e28f8e | ||
|
9b19688d65 | ||
|
e4d77cb9b2 | ||
|
05a9c11c47 | ||
|
9919ccb8b5 | ||
|
661930cbe6 | ||
|
6a2a54dcb5 | ||
|
c9cfda5ef2 | ||
|
4ba7c4a021 | ||
|
74a60ab963 | ||
|
3bc2454e91 | ||
|
a7df79ac07 | ||
|
31866be98b | ||
|
57e22d78e0 | ||
|
a4a6a8469e | ||
|
3158f9c33a | ||
|
711f220397 | ||
|
a223273544 | ||
|
61876ed232 | ||
|
f025671b8a | ||
|
489099ca91 | ||
|
08b4b73c67 | ||
|
fb492d4bb2 | ||
|
f0480c34d7 | ||
|
3395f6081c | ||
|
c9a9a8bc58 | ||
|
fa44e0c06e | ||
|
16e7b5af12 | ||
|
5265c48d04 | ||
|
b9a4053eec | ||
|
1517deeeb6 | ||
|
0dd68d11cb | ||
|
4f37c564a5 | ||
|
5ad2f2873e | ||
|
966971bd12 | ||
|
7767c57087 | ||
|
ba4a84602a | ||
|
d115f9dd1b | ||
|
1ccb934541 | ||
|
434956fc75 | ||
|
7da925ca70 | ||
|
3a7d8efc57 | ||
|
286b1e0ab7 | ||
|
2cbef2b10f | ||
|
d88e9ffd33 | ||
|
7c829852b8 | ||
|
709f1bbd75 | ||
|
8a4bec811b | ||
|
7889b21e7b | ||
|
000af6d9ee | ||
|
07458e5375 | ||
|
e8eb9f9614 | ||
|
e9ab06b59e | ||
|
979c525124 | ||
|
06b25f384a | ||
|
5af5bb2a32 | ||
|
caa5fb75b3 | ||
|
f4d6710a0f | ||
|
b3da5bdaa3 | ||
|
f6d4d00e02 | ||
|
37c97ac8fc | ||
|
5ac20a4d30 | ||
|
45203a4992 | ||
|
bb72229d6a | ||
|
16880de8f6 | ||
|
b20b9727cf | ||
|
e21043e81c | ||
|
1ecf709918 | ||
|
5288a6f9e2 | ||
|
c505652c15 | ||
|
2ebdac70da | ||
|
853b016a42 | ||
|
598b51eb7a | ||
|
985f3b44b7 | ||
|
ea6d8b8bde | ||
|
e1df763940 | ||
|
bb76af4f65 | ||
|
839b3e7392 | ||
|
adfd76f44b | ||
|
df7ff4ef1a | ||
|
c71600c144 | ||
|
5f24fc0986 | ||
|
a53284fe4f | ||
|
4ef05e35b8 | ||
|
956cfaf844 | ||
|
95f991cff3 | ||
|
c4541d8f5b | ||
|
ee29b23bd4 | ||
|
69e944e21a | ||
|
4827655632 | ||
|
5e7a7701b9 | ||
|
eefbfe746f | ||
|
45dfa9f215 | ||
|
64b72a3c9b | ||
|
51e5cc2ac8 | ||
|
2fc4b174c1 | ||
|
bd6c93a811 | ||
|
54971842f2 | ||
|
0fd83f0028 | ||
|
e98bceec10 | ||
|
f51cb6fca9 | ||
|
63f9af307d | ||
|
3453521c9c | ||
|
2744bdcdb7 | ||
|
e87115d462 | ||
|
548e59fc99 | ||
|
6ca5bb4d41 | ||
|
2a8ab1c6ca | ||
|
57f78dc61c | ||
|
388655d19b | ||
|
35b0a9e3ae | ||
|
25b4996145 | ||
|
75079320d1 | ||
|
aac6a21c4e | ||
|
d2c7c83615 | ||
|
1b3021d61c | ||
|
550606177b | ||
|
24910f2363 | ||
|
2ce2201496 | ||
|
9e89a177c7 | ||
|
bd24724560 | ||
|
bc1f8b5db6 | ||
|
6679ecb9d7 | ||
|
f85aa41adc | ||
|
f2d2f7ebe2 | ||
|
b54c7f720c | ||
|
1ef206467f | ||
|
85a407e7b0 | ||
|
8c7c6f3047 | ||
|
9fead39f36 | ||
|
948744538c | ||
|
dc7c64592b | ||
|
47cd054976 | ||
|
132b932ff3 | ||
|
8b8e2825e3 | ||
|
7dcb229ab3 | ||
|
63322989c2 | ||
|
f198d5d110 | ||
|
bdac23564a | ||
|
c741d1a52a | ||
|
8c6c6039a2 | ||
|
099dafc4c2 | ||
|
c5a4921176 | ||
|
6bfc97c95d | ||
|
6ebc5f0bff | ||
|
8614cd77eb | ||
|
1c5e364880 | ||
|
7d67eefdf5 | ||
|
3e5ae79c5a | ||
|
25e4b9a35e | ||
|
a1c7c0ab01 | ||
|
845a0f8e2d | ||
|
19df5c9b50 | ||
|
3b9b9331a8 | ||
|
500ff6be1a | ||
|
18670c69b2 | ||
|
a7043bf7cc | ||
|
15ab9ff9e3 | ||
|
59b93b23e2 | ||
|
e6b3924a5d | ||
|
160df2f2d1 | ||
|
af6a3aa456 | ||
|
cb5bcf4937 | ||
|
a32bfe7d87 | ||
|
5a008c3738 | ||
|
27022e7c39 | ||
|
3b046ee49d | ||
|
f7030b538f | ||
|
d13883ec86 | ||
|
6bc0030699 | ||
|
1d791f81fa | ||
|
4314a286e3 | ||
|
fc06c599bc | ||
|
1f866fcaed | ||
|
12cd0af111 | ||
|
1f5e306760 | ||
|
557e430c7d | ||
|
c946ddc275 | ||
|
563b3b1328 | ||
|
d84bf83419 | ||
|
1b3d583418 | ||
|
809e2f6d07 | ||
|
e52275e37f | ||
|
1981cb7662 | ||
|
d5c733919b | ||
|
d230d332cf | ||
|
13e1f0a561 | ||
|
e8e996182f | ||
|
fc440ba7e7 | ||
|
883ef2414f | ||
|
46c227bf3a | ||
|
36cfe9f857 | ||
|
1d53e7060a | ||
|
6332a4d800 | ||
|
f02d32b718 | ||
|
4a3ed7d0ae | ||
|
71afb5be75 | ||
|
4117118e23 | ||
|
b4a0bff740 | ||
|
14ac6e665c | ||
|
b0204023c0 | ||
|
c9afdae01c | ||
|
a62755182c | ||
|
3987cad9b7 | ||
|
cfd9aee57b | ||
|
d7a29be3ac | ||
|
a833eaa651 | ||
|
3166a04cef | ||
|
bf4acc21be | ||
|
ad7ebd1a8c | ||
|
d10ce6ac7c | ||
|
3d6e25ee5f | ||
|
d0c26fb1a4 | ||
|
f93f02f424 | ||
|
42a62da764 | ||
|
7978cd6d59 | ||
|
8470a55a41 | ||
|
d7a4098b56 | ||
|
af23c9f7cd | ||
|
1dfac3ad63 | ||
|
f1e3314bb7 | ||
|
0adb7af9a0 | ||
|
c19f87f867 | ||
|
da365be5a2 | ||
|
39e8c13afb | ||
|
a4051945fd | ||
|
6dcb293ba0 | ||
|
b83ff3f924 | ||
|
09412ac813 | ||
|
1d39c9d66a | ||
|
16f4583498 | ||
|
2726478467 | ||
|
bac95913e8 | ||
|
ed97b88b04 | ||
|
76114e2748 | ||
|
d00f19663b | ||
|
47aabf4fda | ||
|
d4216d09c6 | ||
|
5bfd9dbaa7 | ||
|
3a8ce99a9d | ||
|
1839082f95 | ||
|
d8af92bda2 | ||
|
09ef0c1f33 | ||
|
a1d064129a | ||
|
28ca5d90d9 | ||
|
a6390007b7 | ||
|
2e8a5aeb23 | ||
|
48efdc3593 | ||
|
005b4c8dd1 | ||
|
d66b495ba8 | ||
|
cb8bf360c4 | ||
|
d4295cfb25 | ||
|
5e131aed80 | ||
|
97243c8a91 | ||
|
274e394d8e | ||
|
1e9077f529 | ||
|
6861d2f3a1 | ||
|
624584f9df | ||
|
4f3a031786 | ||
|
e96d7d48f5 | ||
|
83e7ade714 | ||
|
47e541eaec | ||
|
c1537a1e82 | ||
|
c81322d51a | ||
|
d02c75d019 | ||
|
e98d5d0c0c | ||
|
9de79f0a36 | ||
|
ba2975aac8 | ||
|
3138fa0b40 | ||
|
9545219a23 | ||
|
bd306bdb9f | ||
|
bc70ec1263 | ||
|
3a6733dc98 | ||
|
6d6db77f06 | ||
|
a5a96dd857 | ||
|
87dd0fbdb6 | ||
|
6a95a0cecb | ||
|
60130633f0 | ||
|
7aa9a69c2f | ||
|
ede6dcd4ac | ||
|
e4f688fcfd | ||
|
3e9b0d6018 | ||
|
af28160679 | ||
|
58274c99d4 | ||
|
9b613029e6 | ||
|
844fe3924e | ||
|
0959efd7be | ||
|
ce65fe96ad | ||
|
5ccf3ed714 | ||
|
c48508d590 | ||
|
107f612384 | ||
|
4645033b98 | ||
|
6d33c003fc | ||
|
b1de90fe08 | ||
|
922b65d231 | ||
|
547f92de07 | ||
|
195285ac2f | ||
|
558cbe5b6d | ||
|
44ea8aa681 | ||
|
8de3469957 | ||
|
299949b156 | ||
|
df3bcbb6cb | ||
|
0177c8f1cf | ||
|
4ea79bc396 | ||
|
2f91cb0df7 | ||
|
cb212ba41c | ||
|
72cafe03e9 | ||
|
f8765c6166 | ||
|
dcffe5d992 | ||
|
4e2be07234 | ||
|
23bb45b845 | ||
|
d4041a4a1f | ||
|
16517f019a | ||
|
88e2f739a9 | ||
|
7bef2ad4cc | ||
|
a93c69d150 | ||
|
2e327dfcd7 | ||
|
f134a423f6 | ||
|
97f7e6632d | ||
|
327b8c863e | ||
|
97d177f42a | ||
|
2d0153195e | ||
|
7be4641040 | ||
|
4790db348d | ||
|
4d382a59d0 | ||
|
9fa18fa366 | ||
|
be22886be8 | ||
|
49a91885c9 | ||
|
f522c08438 | ||
|
6b4c331060 | ||
|
2759c3f0db | ||
|
e32f2b0a39 | ||
|
8c6d0759c7 | ||
|
0767bf487e | ||
|
f83b81b8c4 | ||
|
250d99d997 | ||
|
8933022edc | ||
|
dafe775ffa | ||
|
53c1750f0d | ||
|
f3f619cc41 | ||
|
51840a6693 | ||
|
55544845db | ||
|
86ce93b376 | ||
|
39ebb64b85 | ||
|
14cb2d5398 | ||
|
afdd6d39ec | ||
|
b4cbf620ab | ||
|
1ebd4f342e | ||
|
38f7deca78 | ||
|
51ef894a47 | ||
|
1e89369ef8 | ||
|
a2d8305e21 | ||
|
9f84f63471 | ||
|
241b965715 | ||
|
ae681b10e7 | ||
|
980085a8a3 | ||
|
43178dfe10 | ||
|
50a10cf161 | ||
|
cd24f7d30a | ||
|
78e23bd4ec | ||
|
b7c4c960e2 | ||
|
e64c3a1d87 | ||
|
cdcf6cdb25 | ||
|
aa3865c303 | ||
|
11c57e7aee | ||
|
2bb5c5806f | ||
|
365f3d2aa5 | ||
|
102f7ab059 | ||
|
99a2230fdb | ||
|
bf7c035f99 | ||
|
5f5e53a8d5 | ||
|
f4833c6c91 | ||
|
f32414dd93 | ||
|
349e842078 | ||
|
ca8f0f84c4 | ||
|
0f5ebb6827 | ||
|
5ca2a28246 | ||
|
566977c136 | ||
|
15c16ac54e | ||
|
bd75305560 | ||
|
c769924505 | ||
|
a24c6fdb39 | ||
|
d179afa303 | ||
|
723b49a22a | ||
|
e2c6f2f96f | ||
|
e4310a57cd | ||
|
4c7436e328 | ||
|
4360c65ed9 | ||
|
3b1181dae6 | ||
|
e43fe85454 | ||
|
cfc82591da | ||
|
4e5c0e70a6 | ||
|
265fa12917 | ||
|
a3b265a477 | ||
|
41b64cb8a3 | ||
|
a0336ce48b | ||
|
d9538183bd | ||
|
158b323767 | ||
|
6ec72b2978 | ||
|
47ae21c08e | ||
|
e9516ea4dd | ||
|
0785e2910f | ||
|
97ac722b24 | ||
|
7ca0ff9a19 | ||
|
1db02d7f36 | ||
|
204a8f1fcc | ||
|
57d57b8d8f | ||
|
bf34f730dd | ||
|
952f68fed5 | ||
|
7d4658643d | ||
|
a9bdf761e8 | ||
|
30e70c4697 | ||
|
43754c7f17 | ||
|
feb97cfc22 | ||
|
a262c16f06 | ||
|
175b7e8541 | ||
|
867cb225b6 | ||
|
97d8e4571f | ||
|
dc1ceca86e | ||
|
6529fdd28d | ||
|
e4e0a39dad | ||
|
53772ba305 | ||
|
d6598e790c | ||
|
9534969c05 | ||
|
a3b2118906 | ||
|
b4271a3533 | ||
|
79d68a52d0 | ||
|
9a89990293 | ||
|
7ec69e4215 | ||
|
99fbb181c1 | ||
|
4abb3f19bf | ||
|
ddd60e7142 | ||
|
47f408ca7c | ||
|
e3431a2c91 | ||
|
e41809af89 | ||
|
a112e7f9a4 | ||
|
63c087a255 | ||
|
7862b853bf | ||
|
da34491c59 | ||
|
d1b294e1ac | ||
|
b9a11f8c21 | ||
|
b8643f73b7 | ||
|
23651c6142 | ||
|
2696e13b19 | ||
|
446c930823 | ||
|
781209a23b | ||
|
065f707bd7 | ||
|
6c43e9c2e0 | ||
|
747c91210f | ||
|
cd978fa153 | ||
|
12ad588a9b | ||
|
6a0007c410 | ||
|
9dc4f13579 | ||
|
12f1707a74 | ||
|
b4dc060d75 | ||
|
ba51a696d2 | ||
|
52a3764ae4 | ||
|
1e6520fddd | ||
|
6a4470912f | ||
|
8356c2495c | ||
|
722ff4d9c0 | ||
|
a3c5ef59d6 | ||
|
5227483855 | ||
|
21778d057e | ||
|
826503766e | ||
|
1414abfe95 | ||
|
dc51354316 | ||
|
fae9e27365 | ||
|
d500fb8598 | ||
|
c58228195b | ||
|
519e3308ab | ||
|
29662eef5e | ||
|
2730510393 | ||
|
2669c51265 | ||
|
aeb2e282db | ||
|
4d17d95335 | ||
|
bac37d1714 | ||
|
e6e1705852 | ||
|
28d9f82ab1 | ||
|
93f5043230 | ||
|
4239c952d2 | ||
|
e69f878241 | ||
|
6d3aa3276a | ||
|
e3e3a91734 | ||
|
54da2526ed | ||
|
99f2aba6e1 | ||
|
128a00c4ab | ||
|
1d0a448e07 | ||
|
731fd01139 | ||
|
3ef573f67c | ||
|
6bcfc73175 | ||
|
501d081d3b | ||
|
70d85c58e2 | ||
|
a614205663 | ||
|
2c5cba28b6 | ||
|
7aca4e7463 | ||
|
f708a5b016 | ||
|
efd2326a29 | ||
|
d13454fb84 |
28
.gitignore
vendored
28
.gitignore
vendored
@@ -1,31 +1,19 @@
|
|||||||
avatar/*
|
avatar/
|
||||||
files/*
|
files/
|
||||||
file/*
|
file/
|
||||||
local/*
|
local/
|
||||||
_darcs/*
|
logs/
|
||||||
logs/*
|
log/
|
||||||
log/*
|
run/
|
||||||
run/*
|
|
||||||
config.php
|
config.php
|
||||||
.htaccess
|
.htaccess
|
||||||
httpd.conf
|
httpd.conf
|
||||||
*.tmproj
|
|
||||||
dataobject.ini
|
dataobject.ini
|
||||||
*~
|
|
||||||
*.bak
|
*.bak
|
||||||
*.orig
|
*.orig
|
||||||
*.rej
|
*.rej
|
||||||
.#*
|
|
||||||
*.swp
|
|
||||||
.buildpath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
TODO.rym
|
TODO.rym
|
||||||
config-*.php
|
config-*.php
|
||||||
good-config.php
|
good-config.php
|
||||||
lac08.log
|
|
||||||
php.log
|
|
||||||
.DS_Store
|
|
||||||
nbproject
|
|
||||||
*.mo
|
*.mo
|
||||||
|
/vendor/
|
||||||
|
139
CHANGELOG.md
Normal file
139
CHANGELOG.md
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
# GNU social - Log of Changes
|
||||||
|
|
||||||
|
## 2.0.0 - THIS. IS. GNU SOCIAL!!! [WIP]
|
||||||
|
|
||||||
|
Release name chosen after 300 by Frank Miller where the main protagonist Leonidas, King of Sparta, declines peace with the
|
||||||
|
Persians, after being disrespected, by shouting at the Persian Messenger "This is Sparta!" and kicking him into a large well
|
||||||
|
proceeded by the killing of the other Persian messengers.
|
||||||
|
|
||||||
|
### Major changes from previous release:
|
||||||
|
|
||||||
|
Load and Storage:
|
||||||
|
- New media handling system
|
||||||
|
- GS is now structurely divided in includes and public
|
||||||
|
- OEmbed upgraded to Embed plugin (Now we provide Open Graph information too)
|
||||||
|
|
||||||
|
General:
|
||||||
|
- Composer was integrated
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- Restored built-in plugins
|
||||||
|
- New modules system: core plugins and plugins physically separated
|
||||||
|
- Refactor of Plugin API to better illustrate the idea of modules
|
||||||
|
- Bug fixes of core modules logic
|
||||||
|
|
||||||
|
#### TODO before alpha:
|
||||||
|
|
||||||
|
Load and Storage:
|
||||||
|
- Upgrade STOMP queue
|
||||||
|
- Add Redis based caching and queues
|
||||||
|
- Review memcached based cache
|
||||||
|
- Port PEAR DB to PDO_DataObject
|
||||||
|
- Support PostgreSQL
|
||||||
|
|
||||||
|
Network:
|
||||||
|
- Port PEAR HTTP to Guzzle
|
||||||
|
- Port PEAR Mail to PHPSendMail
|
||||||
|
- Add OAuth2 support (deprecate OAuth1)
|
||||||
|
- Add shinny new Plugins management interface for sysadmins together with a new doc for devs
|
||||||
|
|
||||||
|
Federation:
|
||||||
|
- Add ActivityPub support
|
||||||
|
- Fix audience targeting
|
||||||
|
- Add Group Actor Type
|
||||||
|
- OstatusSub: Remote follow OS and AP profiles via OStatusSub
|
||||||
|
- ActorLists: Allow to create collections of Actors and to interact with them - supports both OS and AP
|
||||||
|
- The Free Network: Automagically migrate internal remote profiles between Free Network protocols (check Nodeinfo)
|
||||||
|
- Enable the search box to import remote notices and profiles
|
||||||
|
|
||||||
|
General:
|
||||||
|
- Fix failling unit tests
|
||||||
|
- Improve Cronish
|
||||||
|
- Run session garbage collection
|
||||||
|
- Cleanup Email Registration
|
||||||
|
- Refactoring of confirmation codes
|
||||||
|
- Refactoring of Exceptions
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- Document conversion of older plugins to the new GS 2
|
||||||
|
- Create installer for v2 plugins
|
||||||
|
- Introduce new metadata for plugins (category and thumb)
|
||||||
|
- Improve plugin management tool (add install form and better UI that makes use of new metadata)
|
||||||
|
- Add plugin management tool as a install step
|
||||||
|
- Allow to install remote plugins and suggest popular trusted ones
|
||||||
|
|
||||||
|
## v1.20.9release - The Invicta Crusade
|
||||||
|
|
||||||
|
Release name chosen after Porto city. Porto is one of the oldest cities in Europe and thanks to its fierce resistance
|
||||||
|
during two battles and sieges in history, it has earned the epithet of ‘Cidade Invicta’ (Invincible City). The dev team
|
||||||
|
behind this release studies in Porto, Portugal.
|
||||||
|
|
||||||
|
Dropped Support for PHP5.6.x. Minimum PHP version now is 7.0.0.
|
||||||
|
|
||||||
|
Major changes from previous release:
|
||||||
|
|
||||||
|
- Various patches on PEAR related components
|
||||||
|
- Various database related improvements
|
||||||
|
- Improved XMPP support
|
||||||
|
- Added Nodeinfo support
|
||||||
|
- Various i18n and l10n bug fixes
|
||||||
|
- Improvements on Internal Session Handler
|
||||||
|
- Improvements on OpenID support
|
||||||
|
- Improved Media handling and safer upload
|
||||||
|
- Redirect to previous page after login
|
||||||
|
- Initial work on full conversion to PHP7
|
||||||
|
- Initial work on a better documentation
|
||||||
|
- Allow login with email
|
||||||
|
- Various bug fixes
|
||||||
|
|
||||||
|
## v1.2.0beta4 - The good reign of PHP5
|
||||||
|
|
||||||
|
Dropped support for PHP5.4.
|
||||||
|
|
||||||
|
New this version
|
||||||
|
|
||||||
|
This is the development branch for the 1.2.x version of GNU social. All daring 1.1.x admins should upgrade to this version.
|
||||||
|
|
||||||
|
So far it includes the following changes:
|
||||||
|
|
||||||
|
- Backing up a user's account is more and more complete.
|
||||||
|
- Emojis 😸 (utf8mb4 support)
|
||||||
|
|
||||||
|
The last release, 1.1.3, gave us these improvements:
|
||||||
|
|
||||||
|
- XSS security fix (thanks Simon Waters, https://www.surevine.com/)
|
||||||
|
- Many improvements to ease adoption of the Qvitter front-end https://github.com/hannesmannerheim/qvitter
|
||||||
|
- Protocol adaptions for improved performance and stability
|
||||||
|
|
||||||
|
Upgrades from StatusNet 1.1.1 will also experience these improvements:
|
||||||
|
|
||||||
|
- Fixes for SQL injection errors in profile lists.
|
||||||
|
- Improved ActivityStreams JSON representation of activities and objects.
|
||||||
|
- Upgrade to the Twitter 1.1 API.
|
||||||
|
- More robust handling of errors in distribution.
|
||||||
|
- Fix error in OStatus subscription for remote groups.
|
||||||
|
- Fix error in XMPP distribution.
|
||||||
|
- Tracking of conversation URI metadata (more coherent convos)
|
||||||
|
|
||||||
|
## v1.1.3release - The Spanish Invasion
|
||||||
|
|
||||||
|
New this version
|
||||||
|
|
||||||
|
This is a security fix and bug fix release since 1.1.3-beta2. All 1.1.x sites should upgrade to this version.
|
||||||
|
|
||||||
|
So far it includes the following changes:
|
||||||
|
|
||||||
|
- XSS security fix (thanks Simon Waters, https://www.surevine.com/)
|
||||||
|
- Many improvements to ease adoption of the Qvitter front-end https://github.com/hannesmannerheim/qvitter
|
||||||
|
- Protocol adaptions for improved performance and stability
|
||||||
|
- Backing up a user's account now appears to work as it should
|
||||||
|
|
||||||
|
Upgrades from StatusNet 1.1.1 will also experience these improvements:
|
||||||
|
|
||||||
|
- Fixes for SQL injection errors in profile lists.
|
||||||
|
- Improved ActivityStreams JSON representation of activities and objects.
|
||||||
|
- Upgrade to the Twitter 1.1 API.
|
||||||
|
- More robust handling of errors in distribution.
|
||||||
|
- Fix error in OStatus subscription for remote groups.
|
||||||
|
- Fix error in XMPP distribution.
|
||||||
|
- Tracking of conversation URI metadata (more coherent convos)
|
95
CODE_OF_CONDUCT.md
Normal file
95
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
## 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."
|
784
CONFIGURE
784
CONFIGURE
@@ -1,784 +0,0 @@
|
|||||||
Configuration options
|
|
||||||
=====================
|
|
||||||
|
|
||||||
The main configuration file for StatusNet (excepting configurations for
|
|
||||||
dependency software) is config.php in your StatusNet directory. If you
|
|
||||||
edit any other file in the directory, like lib/default.php (where most
|
|
||||||
of the defaults are defined), you will lose your configuration options
|
|
||||||
in any upgrade, and you will wish that you had been more careful.
|
|
||||||
|
|
||||||
Starting with version 0.9.0, a Web based configuration panel has been
|
|
||||||
added to StatusNet. The preferred method for changing config options is
|
|
||||||
to use this panel.
|
|
||||||
|
|
||||||
A command-line script, setconfig.php, can be used to set individual
|
|
||||||
configuration options. It's in the scripts/ directory.
|
|
||||||
|
|
||||||
Starting with version 0.7.1, you can put config files in the
|
|
||||||
/etc/statusnet/ directory on your server, if it exists. Config files
|
|
||||||
will be included in this order:
|
|
||||||
|
|
||||||
* /etc/statusnet/statusnet.php - server-wide config
|
|
||||||
* /etc/statusnet/<servername>.php - for a virtual host
|
|
||||||
* /etc/statusnet/<servername>_<pathname>.php - for a path
|
|
||||||
* INSTALLDIR/config.php - for a particular implementation
|
|
||||||
|
|
||||||
Almost all configuration options are made through a two-dimensional
|
|
||||||
associative array, cleverly named $config. A typical configuration
|
|
||||||
line will be:
|
|
||||||
|
|
||||||
$config['section']['option'] = value;
|
|
||||||
|
|
||||||
For brevity, the following documentation describes each section and
|
|
||||||
option.
|
|
||||||
|
|
||||||
site
|
|
||||||
----
|
|
||||||
|
|
||||||
This section is a catch-all for site-wide variables.
|
|
||||||
|
|
||||||
name: the name of your site, like 'YourCompany Microblog'.
|
|
||||||
server: the server part of your site's URLs, like 'example.net'.
|
|
||||||
path: The path part of your site's URLs, like 'statusnet' or ''
|
|
||||||
(installed in root).
|
|
||||||
fancy: whether or not your site uses fancy URLs (see Fancy URLs
|
|
||||||
section above). Default is false.
|
|
||||||
logfile: full path to a file for StatusNet to save logging
|
|
||||||
information to. You may want to use this if you don't have
|
|
||||||
access to syslog.
|
|
||||||
logdebug: whether to log additional debug info like backtraces on
|
|
||||||
hard errors. Default false.
|
|
||||||
locale_path: full path to the directory for locale data. Unless you
|
|
||||||
store all your locale data in one place, you probably
|
|
||||||
don't need to use this.
|
|
||||||
language: default language for your site. Defaults to US English.
|
|
||||||
Note that this is overridden if a user is logged in and has
|
|
||||||
selected a different language. It is also overridden if the
|
|
||||||
user is NOT logged in, but their browser requests a different
|
|
||||||
langauge. Since pretty much everybody's browser requests a
|
|
||||||
language, that means that changing this setting has little or
|
|
||||||
no effect in practice.
|
|
||||||
languages: A list of languages supported on your site. Typically you'd
|
|
||||||
only change this if you wanted to disable support for one
|
|
||||||
or another language:
|
|
||||||
"unset($config['site']['languages']['de'])" will disable
|
|
||||||
support for German.
|
|
||||||
theme: Theme for your site (see Theme section). Two themes are
|
|
||||||
provided by default: 'default' and 'stoica' (the one used by
|
|
||||||
Identi.ca). It's appreciated if you don't use the 'stoica' theme
|
|
||||||
except as the basis for your own.
|
|
||||||
email: contact email address for your site. By default, it's extracted
|
|
||||||
from your Web server environment; you may want to customize it.
|
|
||||||
broughtbyurl: name of an organization or individual who provides the
|
|
||||||
service. Each page will include a link to this name in the
|
|
||||||
footer. A good way to link to the blog, forum, wiki,
|
|
||||||
corporate portal, or whoever is making the service available.
|
|
||||||
broughtby: text used for the "brought by" link.
|
|
||||||
timezone: default timezone for message display. Users can set their
|
|
||||||
own time zone. Defaults to 'UTC', which is a pretty good default.
|
|
||||||
closed: If set to 'true', will disallow registration on your site.
|
|
||||||
This is a cheap way to restrict accounts to only one
|
|
||||||
individual or group; just register the accounts you want on
|
|
||||||
the service, *then* set this variable to 'true'.
|
|
||||||
inviteonly: If set to 'true', will only allow registration if the user
|
|
||||||
was invited by an existing user.
|
|
||||||
private: If set to 'true', anonymous users will be redirected to the
|
|
||||||
'login' page. Also, API methods that normally require no
|
|
||||||
authentication will require it. Note that this does not turn
|
|
||||||
off registration; use 'closed' or 'inviteonly' for the
|
|
||||||
behaviour you want.
|
|
||||||
notice: A plain string that will appear on every page. A good place
|
|
||||||
to put introductory information about your service, or info about
|
|
||||||
upgrades and outages, or other community info. Any HTML will
|
|
||||||
be escaped.
|
|
||||||
logo: URL of an image file to use as the logo for the site. Overrides
|
|
||||||
the logo in the theme, if any.
|
|
||||||
ssllogo: URL of an image file to use as the logo on SSL pages. If unset,
|
|
||||||
theme logo is used instead.
|
|
||||||
ssl: Whether to use SSL and https:// URLs for some or all pages.
|
|
||||||
Possible values are 'always' (use it for all pages), 'never'
|
|
||||||
(don't use it for any pages), or 'sometimes' (use it for
|
|
||||||
sensitive pages that include passwords like login and registration,
|
|
||||||
but not for regular pages). Default to 'never'.
|
|
||||||
sslproxy: Whether to force GNUsocial to think it is HTTPS when the
|
|
||||||
server gives no such information. I.e. when you're using a reverse
|
|
||||||
proxy that adds the encryption layer but the webserver that runs PHP
|
|
||||||
isn't configured with a key and certificate.
|
|
||||||
sslserver: use an alternate server name for SSL URLs, like
|
|
||||||
'secure.example.org'. You should be careful to set cookie
|
|
||||||
parameters correctly so that both the SSL server and the
|
|
||||||
"normal" server can access the session cookie and
|
|
||||||
preferably other cookies as well.
|
|
||||||
shorturllength: ignored. See 'url' section below.
|
|
||||||
dupelimit: minimum time allowed for one person to say the same thing
|
|
||||||
twice. Default 60s. Anything lower is considered a user
|
|
||||||
or UI error.
|
|
||||||
textlimit: default max size for texts in the site. Defaults to 0 (no limit).
|
|
||||||
Can be fine-tuned for notices, messages, profile bios and group descriptions.
|
|
||||||
|
|
||||||
db
|
|
||||||
--
|
|
||||||
|
|
||||||
This section is a reference to the configuration options for
|
|
||||||
DB_DataObject (see <http://ur1.ca/7xp>). The ones that you may want to
|
|
||||||
set are listed below for clarity.
|
|
||||||
|
|
||||||
database: a DSN (Data Source Name) for your StatusNet database. This is
|
|
||||||
in the format 'protocol://username:password@hostname/databasename',
|
|
||||||
where 'protocol' is 'mysql' or 'mysqli' (or possibly 'postgresql', if you
|
|
||||||
really know what you're doing), 'username' is the username,
|
|
||||||
'password' is the password, and etc.
|
|
||||||
ini_yourdbname: if your database is not named 'statusnet', you'll need
|
|
||||||
to set this to point to the location of the
|
|
||||||
statusnet.ini file. Note that the real name of your database
|
|
||||||
should go in there, not literally 'yourdbname'.
|
|
||||||
db_driver: You can try changing this to 'MDB2' to use the other driver
|
|
||||||
type for DB_DataObject, but note that it breaks the OpenID
|
|
||||||
libraries, which only support PEAR::DB.
|
|
||||||
debug: On a database error, you may get a message saying to set this
|
|
||||||
value to 5 to see debug messages in the browser. This breaks
|
|
||||||
just about all pages, and will also expose the username and
|
|
||||||
password
|
|
||||||
quote_identifiers: Set this to true if you're using postgresql.
|
|
||||||
type: either 'mysql' or 'postgresql' (used for some bits of
|
|
||||||
database-type-specific SQL in the code). Defaults to mysql.
|
|
||||||
mirror: you can set this to an array of DSNs, like the above
|
|
||||||
'database' value. If it's set, certain read-only actions will
|
|
||||||
use a random value out of this array for the database, rather
|
|
||||||
than the one in 'database' (actually, 'database' is overwritten).
|
|
||||||
You can offload a busy DB server by setting up MySQL replication
|
|
||||||
and adding the slaves to this array. Note that if you want some
|
|
||||||
requests to go to the 'database' (master) server, you'll need
|
|
||||||
to include it in this array, too.
|
|
||||||
utf8: whether to talk to the database in UTF-8 mode. This is the default
|
|
||||||
with new installations, but older sites may want to turn it off
|
|
||||||
until they get their databases fixed up. See "UTF-8 database"
|
|
||||||
above for details.
|
|
||||||
schemacheck: when to let plugins check the database schema to add
|
|
||||||
tables or update them. Values can be 'runtime' (default)
|
|
||||||
or 'script'. 'runtime' can be costly (plugins check the
|
|
||||||
schema on every hit, adding potentially several db
|
|
||||||
queries, some quite long), but not everyone knows how to
|
|
||||||
run a script. If you can, set this to 'script' and run
|
|
||||||
scripts/checkschema.php whenever you install or upgrade a
|
|
||||||
plugin.
|
|
||||||
|
|
||||||
syslog
|
|
||||||
------
|
|
||||||
|
|
||||||
By default, StatusNet sites log error messages to the syslog facility.
|
|
||||||
(You can override this using the 'logfile' parameter described above).
|
|
||||||
|
|
||||||
appname: The name that StatusNet uses to log messages. By default it's
|
|
||||||
"statusnet", but if you have more than one installation on the
|
|
||||||
server, you may want to change the name for each instance so
|
|
||||||
you can track log messages more easily.
|
|
||||||
priority: level to log at. Currently ignored.
|
|
||||||
facility: what syslog facility to used. Defaults to LOG_USER, only
|
|
||||||
reset if you know what syslog is and have a good reason
|
|
||||||
to change it.
|
|
||||||
|
|
||||||
queue
|
|
||||||
-----
|
|
||||||
|
|
||||||
You can configure the software to queue time-consuming tasks, like
|
|
||||||
sending out SMS email or XMPP messages, for off-line processing. See
|
|
||||||
'Queues and daemons' above for how to set this up.
|
|
||||||
|
|
||||||
enabled: Whether to uses queues. Defaults to false.
|
|
||||||
daemon: Wather to use queuedaemon. Defaults to false, which means
|
|
||||||
you'll use OpportunisticQM plugin.
|
|
||||||
subsystem: Which kind of queueserver to use. Values include "db" for
|
|
||||||
our hacked-together database queuing (no other server
|
|
||||||
required) and "stomp" for a stomp server.
|
|
||||||
stomp_server: "broker URI" for stomp server. Something like
|
|
||||||
"tcp://hostname:61613". More complicated ones are
|
|
||||||
possible; see your stomp server's documentation for
|
|
||||||
details.
|
|
||||||
queue_basename: a root name to use for queues (stomp only). Typically
|
|
||||||
something like '/queue/sitename/' makes sense. If running
|
|
||||||
multiple instances on the same server, make sure that
|
|
||||||
either this setting or $config['site']['nickname'] are
|
|
||||||
unique for each site to keep them separate.
|
|
||||||
|
|
||||||
stomp_username: username for connecting to the stomp server; defaults
|
|
||||||
to null.
|
|
||||||
stomp_password: password for connecting to the stomp server; defaults
|
|
||||||
to null.
|
|
||||||
|
|
||||||
stomp_persistent: keep items across queue server restart, if enabled.
|
|
||||||
Under ActiveMQ, the server configuration determines if and how
|
|
||||||
persistent storage is actually saved.
|
|
||||||
|
|
||||||
If using a message queue server other than ActiveMQ, you may
|
|
||||||
need to disable this if it does not support persistence.
|
|
||||||
|
|
||||||
stomp_transactions: use transactions to aid in error detection.
|
|
||||||
A broken transaction will be seen quickly, allowing a message
|
|
||||||
to be redelivered immediately if a daemon crashes.
|
|
||||||
|
|
||||||
If using a message queue server other than ActiveMQ, you may
|
|
||||||
need to disable this if it does not support transactions.
|
|
||||||
|
|
||||||
stomp_acks: send acknowledgements to aid in flow control.
|
|
||||||
An acknowledgement of successful processing tells the server
|
|
||||||
we're ready for more and can help keep things moving smoothly.
|
|
||||||
|
|
||||||
This should *not* be turned off when running with ActiveMQ, but
|
|
||||||
if using another message queue server that does not support
|
|
||||||
acknowledgements you might need to disable this.
|
|
||||||
|
|
||||||
softlimit: an absolute or relative "soft memory limit"; daemons will
|
|
||||||
restart themselves gracefully when they find they've hit
|
|
||||||
this amount of memory usage. Defaults to 90% of PHP's global
|
|
||||||
memory_limit setting.
|
|
||||||
|
|
||||||
inboxes: delivery of messages to receiver's inboxes can be delayed to
|
|
||||||
queue time for best interactive performance on the sender.
|
|
||||||
This may however be annoyingly slow when using the DB queues,
|
|
||||||
so you can set this to false if it's causing trouble.
|
|
||||||
|
|
||||||
breakout: for stomp, individual queues are by default grouped up for
|
|
||||||
best scalability. If some need to be run by separate daemons,
|
|
||||||
etc they can be manually adjusted here.
|
|
||||||
|
|
||||||
Default will share all queues for all sites within each group.
|
|
||||||
Specify as <group>/<queue> or <group>/<queue>/<site>,
|
|
||||||
using nickname identifier as site.
|
|
||||||
|
|
||||||
'main/distrib' separate "distrib" queue covering all sites
|
|
||||||
'xmpp/xmppout/mysite' separate "xmppout" queue covering just 'mysite'
|
|
||||||
|
|
||||||
max_retries: for stomp, drop messages after N failed attempts to process.
|
|
||||||
Defaults to 10.
|
|
||||||
|
|
||||||
dead_letter_dir: for stomp, optional directory to dump data on failed
|
|
||||||
queue processing events after discarding them.
|
|
||||||
|
|
||||||
stomp_no_transactions: for stomp, the server does not support transactions,
|
|
||||||
so do not try to user them. This is needed for http://www.morbidq.com/.
|
|
||||||
|
|
||||||
stomp_no_acks: for stomp, the server does not support acknowledgements.
|
|
||||||
so do not try to user them. This is needed for http://www.morbidq.com/.
|
|
||||||
|
|
||||||
license
|
|
||||||
-------
|
|
||||||
|
|
||||||
The default license to use for your users notices. The default is the
|
|
||||||
Creative Commons Attribution 3.0 license, which is probably the right
|
|
||||||
choice for any public site. Note that some other servers will not
|
|
||||||
accept notices if you apply a stricter license than this.
|
|
||||||
|
|
||||||
type: one of 'cc' (for Creative Commons licenses), 'allrightsreserved'
|
|
||||||
(default copyright), or 'private' (for private and confidential
|
|
||||||
information).
|
|
||||||
owner: for 'allrightsreserved' or 'private', an assigned copyright
|
|
||||||
holder (for example, an employer for a private site). If
|
|
||||||
not specified, will be attributed to 'contributors'.
|
|
||||||
url: URL of the license, used for links.
|
|
||||||
title: Title for the license, like 'Creative Commons Attribution 3.0'.
|
|
||||||
image: A button shown on each page for the license.
|
|
||||||
|
|
||||||
mail
|
|
||||||
----
|
|
||||||
|
|
||||||
This is for configuring out-going email. We use PEAR's Mail module,
|
|
||||||
see: http://pear.php.net/manual/en/package.mail.mail.factory.php
|
|
||||||
|
|
||||||
backend: the backend to use for mail, one of 'mail', 'sendmail', and
|
|
||||||
'smtp'. Defaults to PEAR's default, 'mail'.
|
|
||||||
params: if the mail backend requires any parameters, you can provide
|
|
||||||
them in an associative array.
|
|
||||||
|
|
||||||
nickname
|
|
||||||
--------
|
|
||||||
|
|
||||||
This is for configuring nicknames in the service.
|
|
||||||
|
|
||||||
blacklist: an array of strings for usernames that may not be
|
|
||||||
registered. A default array exists for strings that are
|
|
||||||
used by StatusNet (e.g. 'doc', 'main', 'avatar', 'theme')
|
|
||||||
but you may want to add others if you have other software
|
|
||||||
installed in a subdirectory of StatusNet or if you just
|
|
||||||
don't want certain words used as usernames.
|
|
||||||
featured: an array of nicknames of 'featured' users of the site.
|
|
||||||
Can be useful to draw attention to well-known users, or
|
|
||||||
interesting people, or whatever.
|
|
||||||
|
|
||||||
avatar
|
|
||||||
------
|
|
||||||
|
|
||||||
For configuring avatar access.
|
|
||||||
|
|
||||||
dir: Directory to look for avatar files and to put them into.
|
|
||||||
Defaults to avatar subdirectory of install directory; if
|
|
||||||
you change it, make sure to change path, too.
|
|
||||||
path: Path to avatars. Defaults to path for avatar subdirectory,
|
|
||||||
but you can change it if you wish. Note that this will
|
|
||||||
be included with the avatar server, too.
|
|
||||||
server: If set, defines another server where avatars are stored in the
|
|
||||||
root directory. Note that the 'avatar' subdir still has to be
|
|
||||||
writeable. You'd typically use this to split HTTP requests on
|
|
||||||
the client to speed up page loading, either with another
|
|
||||||
virtual server or with an NFS or SAMBA share. Clients
|
|
||||||
typically only make 2 connections to a single server at a
|
|
||||||
time <http://ur1.ca/6ih>, so this can parallelize the job.
|
|
||||||
Defaults to null.
|
|
||||||
ssl: Whether to access avatars using HTTPS. Defaults to null, meaning
|
|
||||||
to guess based on site-wide SSL settings.
|
|
||||||
|
|
||||||
public
|
|
||||||
------
|
|
||||||
|
|
||||||
For configuring the public stream.
|
|
||||||
|
|
||||||
localonly: If set to true, only messages posted by users of this
|
|
||||||
service (rather than other services, filtered through OStatus)
|
|
||||||
are shown in the public stream. Default true.
|
|
||||||
blacklist: An array of IDs of users to hide from the public stream.
|
|
||||||
Useful if you have someone making excessive Twitterfeed posts
|
|
||||||
to the site, other kinds of automated posts, testing bots, etc.
|
|
||||||
autosource: Sources of notices that are from automatic posters, and thus
|
|
||||||
should be kept off the public timeline. Default empty.
|
|
||||||
|
|
||||||
theme
|
|
||||||
-----
|
|
||||||
|
|
||||||
server: Like avatars, you can speed up page loading by pointing the
|
|
||||||
theme file lookup to another server (virtual or real).
|
|
||||||
Defaults to NULL, meaning to use the site server.
|
|
||||||
dir: Directory where theme files are stored. Used to determine
|
|
||||||
whether to show parts of a theme file. Defaults to the theme
|
|
||||||
subdirectory of the install directory.
|
|
||||||
path: Path part of theme URLs, before the theme name. Relative to the
|
|
||||||
theme server. It may make sense to change this path when upgrading,
|
|
||||||
(using version numbers as the path) to make sure that all files are
|
|
||||||
reloaded by caching clients or proxies. Defaults to null,
|
|
||||||
which means to use the site path + '/theme'.
|
|
||||||
ssl: Whether to use SSL for theme elements. Default is null, which means
|
|
||||||
guess based on site SSL settings.
|
|
||||||
sslserver: SSL server to use when page is HTTPS-encrypted. If
|
|
||||||
unspecified, site ssl server and so on will be used.
|
|
||||||
sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
|
|
||||||
|
|
||||||
javascript
|
|
||||||
----------
|
|
||||||
|
|
||||||
server: You can speed up page loading by pointing the
|
|
||||||
theme file lookup to another server (virtual or real).
|
|
||||||
Defaults to NULL, meaning to use the site server.
|
|
||||||
path: Path part of Javascript URLs. Defaults to null,
|
|
||||||
which means to use the site path + '/js/'.
|
|
||||||
ssl: Whether to use SSL for JavaScript files. Default is null, which means
|
|
||||||
guess based on site SSL settings.
|
|
||||||
sslserver: SSL server to use when page is HTTPS-encrypted. If
|
|
||||||
unspecified, site ssl server and so on will be used.
|
|
||||||
sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
|
|
||||||
bustframes: If true, all web pages will break out of framesets. If false,
|
|
||||||
can comfortably live in a frame or iframe... probably. Default
|
|
||||||
to true.
|
|
||||||
|
|
||||||
xmpp
|
|
||||||
----
|
|
||||||
|
|
||||||
For configuring the XMPP sub-system.
|
|
||||||
|
|
||||||
enabled: Whether to accept and send messages by XMPP. Default false.
|
|
||||||
server: server part of XMPP ID for update user.
|
|
||||||
port: connection port for clients. Default 5222, which you probably
|
|
||||||
shouldn't need to change.
|
|
||||||
user: username for the client connection. Users will receive messages
|
|
||||||
from 'user'@'server'.
|
|
||||||
resource: a unique identifier for the connection to the server. This
|
|
||||||
is actually used as a prefix for each XMPP component in the system.
|
|
||||||
password: password for the user account.
|
|
||||||
host: some XMPP domains are served by machines with a different
|
|
||||||
hostname. (For example, @gmail.com GTalk users connect to
|
|
||||||
talk.google.com). Set this to the correct hostname if that's the
|
|
||||||
case with your server.
|
|
||||||
encryption: Whether to encrypt the connection between StatusNet and the
|
|
||||||
XMPP server. Defaults to true, but you can get
|
|
||||||
considerably better performance turning it off if you're
|
|
||||||
connecting to a server on the same machine or on a
|
|
||||||
protected network.
|
|
||||||
debug: if turned on, this will make the XMPP library blurt out all of
|
|
||||||
the incoming and outgoing messages as XML stanzas. Use as a
|
|
||||||
last resort, and never turn it on if you don't have queues
|
|
||||||
enabled, since it will spit out sensitive data to the browser.
|
|
||||||
public: an array of JIDs to send _all_ notices to. This is useful for
|
|
||||||
participating in third-party search and archiving services.
|
|
||||||
|
|
||||||
invite
|
|
||||||
------
|
|
||||||
|
|
||||||
For configuring invites.
|
|
||||||
|
|
||||||
enabled: Whether to allow users to send invites. Default true.
|
|
||||||
|
|
||||||
tag
|
|
||||||
---
|
|
||||||
|
|
||||||
Miscellaneous tagging stuff.
|
|
||||||
|
|
||||||
dropoff: Decay factor for tag listing, in seconds.
|
|
||||||
Defaults to exponential decay over ten days; you can twiddle
|
|
||||||
with it to try and get better results for your site.
|
|
||||||
|
|
||||||
popular
|
|
||||||
-------
|
|
||||||
|
|
||||||
Settings for the "popular" section of the site.
|
|
||||||
|
|
||||||
dropoff: Decay factor for popularity listing, in seconds.
|
|
||||||
Defaults to exponential decay over ten days; you can twiddle
|
|
||||||
with it to try and get better results for your site.
|
|
||||||
|
|
||||||
daemon
|
|
||||||
------
|
|
||||||
|
|
||||||
For daemon processes.
|
|
||||||
|
|
||||||
piddir: directory that daemon processes should write their PID file
|
|
||||||
(process ID) to. Defaults to /var/run/, which is where this
|
|
||||||
stuff should usually go on Unix-ish systems.
|
|
||||||
user: If set, the daemons will try to change their effective user ID
|
|
||||||
to this user before running. Probably a good idea, especially if
|
|
||||||
you start the daemons as root. Note: user name, like 'daemon',
|
|
||||||
not 1001.
|
|
||||||
group: If set, the daemons will try to change their effective group ID
|
|
||||||
to this named group. Again, a name, not a numerical ID.
|
|
||||||
|
|
||||||
emailpost
|
|
||||||
---------
|
|
||||||
|
|
||||||
For post-by-email.
|
|
||||||
|
|
||||||
enabled: Whether to enable post-by-email. Defaults to true. You will
|
|
||||||
also need to set up maildaemon.php.
|
|
||||||
|
|
||||||
sms
|
|
||||||
---
|
|
||||||
|
|
||||||
For SMS integration.
|
|
||||||
|
|
||||||
enabled: Whether to enable SMS integration. Defaults to true. Queues
|
|
||||||
should also be enabled.
|
|
||||||
|
|
||||||
integration
|
|
||||||
-----------
|
|
||||||
|
|
||||||
A catch-all for integration with other systems.
|
|
||||||
|
|
||||||
taguri: base for tag:// URIs. Defaults to site-server + ',2009'.
|
|
||||||
|
|
||||||
inboxes
|
|
||||||
-------
|
|
||||||
|
|
||||||
For notice inboxes.
|
|
||||||
|
|
||||||
enabled: No longer used. If you set this to something other than true,
|
|
||||||
StatusNet will no longer run.
|
|
||||||
|
|
||||||
throttle
|
|
||||||
--------
|
|
||||||
|
|
||||||
For notice-posting throttles.
|
|
||||||
|
|
||||||
enabled: Whether to throttle posting. Defaults to false.
|
|
||||||
count: Each user can make this many posts in 'timespan' seconds. So, if count
|
|
||||||
is 100 and timespan is 3600, then there can be only 100 posts
|
|
||||||
from a user every hour.
|
|
||||||
timespan: see 'count'.
|
|
||||||
|
|
||||||
profile
|
|
||||||
-------
|
|
||||||
|
|
||||||
Profile management.
|
|
||||||
|
|
||||||
biolimit: max character length of bio; 0 means no limit; null means to use
|
|
||||||
the site text limit default.
|
|
||||||
backup: whether users can backup their own profiles. Defaults to true.
|
|
||||||
restore: whether users can restore their profiles from backup files. Defaults
|
|
||||||
to true.
|
|
||||||
delete: whether users can delete their own accounts. Defaults to false.
|
|
||||||
move: whether users can move their accounts to another server. Defaults
|
|
||||||
to true.
|
|
||||||
|
|
||||||
newuser
|
|
||||||
-------
|
|
||||||
|
|
||||||
Options with new users.
|
|
||||||
|
|
||||||
default: nickname of a user account to automatically subscribe new
|
|
||||||
users to. Typically this would be system account for e.g.
|
|
||||||
service updates or announcements. Users are able to unsub
|
|
||||||
if they want. Default is null; no auto subscribe.
|
|
||||||
welcome: nickname of a user account that sends welcome messages to new
|
|
||||||
users. Can be the same as 'default' account, although on
|
|
||||||
busy servers it may be a good idea to keep that one just for
|
|
||||||
'urgent' messages. Default is null; no message.
|
|
||||||
|
|
||||||
If either of these special user accounts are specified, the users should
|
|
||||||
be created before the configuration is updated.
|
|
||||||
|
|
||||||
attachments
|
|
||||||
-----------
|
|
||||||
|
|
||||||
The software lets users upload files with their notices. You can configure
|
|
||||||
the types of accepted files by mime types and a trio of quota options:
|
|
||||||
per file, per user (total), per user per month.
|
|
||||||
|
|
||||||
We suggest the use of the pecl file_info extension to handle mime type
|
|
||||||
detection.
|
|
||||||
|
|
||||||
supported: an array of mime types you accept to store and distribute,
|
|
||||||
like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
|
|
||||||
setup your server to properly recognize the types you want to
|
|
||||||
support.
|
|
||||||
uploads: false to disable uploading files with notices (true by default).
|
|
||||||
|
|
||||||
For quotas, be sure you've set the upload_max_filesize and post_max_size
|
|
||||||
in php.ini to be large enough to handle your upload. In httpd.conf
|
|
||||||
(if you're using apache), check that the LimitRequestBody directive isn't
|
|
||||||
set too low (it's optional, so it may not be there at all).
|
|
||||||
|
|
||||||
process_links: follow redirects and save all available file information
|
|
||||||
(mimetype, date, size, oembed, etc.). Defaults to true.
|
|
||||||
file_quota: maximum size for a single file upload in bytes. A user can send
|
|
||||||
any amount of notices with attachments as long as each attachment
|
|
||||||
is smaller than file_quota.
|
|
||||||
user_quota: total size in bytes a user can store on this server. Each user
|
|
||||||
can store any number of files as long as their total size does
|
|
||||||
not exceed the user_quota.
|
|
||||||
monthly_quota: total size permitted in the current month. This is the total
|
|
||||||
size in bytes that a user can upload each month.
|
|
||||||
dir: directory accessible to the Web process where uploads should go.
|
|
||||||
Defaults to the 'file' subdirectory of the install directory, which
|
|
||||||
should be writeable by the Web user.
|
|
||||||
server: server name to use when creating URLs for uploaded files.
|
|
||||||
Defaults to null, meaning to use the default Web server. Using
|
|
||||||
a virtual server here can speed up Web performance.
|
|
||||||
path: URL path, relative to the server, to find files. Defaults to
|
|
||||||
main path + '/file/'.
|
|
||||||
ssl: whether to use HTTPS for file URLs. Defaults to null, meaning to
|
|
||||||
guess based on other SSL settings.
|
|
||||||
sslserver: if specified, this server will be used when creating HTTPS
|
|
||||||
URLs. Otherwise, the site SSL server will be used, with /file/ path.
|
|
||||||
sslpath: if this and the sslserver are specified, this path will be used
|
|
||||||
when creating HTTPS URLs. Otherwise, the attachments|path value
|
|
||||||
will be used.
|
|
||||||
show_thumbs: show thumbnails in notice lists for uploaded images, and photos
|
|
||||||
and videos linked remotely that provide oEmbed info. Defaults to true.
|
|
||||||
show_html: show (filtered) text/html attachments (and oEmbed HTML etc.).
|
|
||||||
Doesn't affect AJAX calls. Defaults to false.
|
|
||||||
filename_base: for new files, choose one: 'upload', 'hash'. Defaults to hash.
|
|
||||||
|
|
||||||
group
|
|
||||||
-----
|
|
||||||
|
|
||||||
Options for group functionality.
|
|
||||||
|
|
||||||
maxaliases: maximum number of aliases a group can have. Default 3. Set
|
|
||||||
to 0 or less to prevent aliases in a group.
|
|
||||||
desclimit: maximum number of characters to allow in group descriptions.
|
|
||||||
null (default) means to use the site-wide text limits. 0
|
|
||||||
means no limit.
|
|
||||||
addtag: Whether to add a tag for the group nickname for every group post
|
|
||||||
(pre-1.0.x behaviour). Defaults to false.
|
|
||||||
|
|
||||||
search
|
|
||||||
------
|
|
||||||
|
|
||||||
Some stuff for search.
|
|
||||||
|
|
||||||
type: type of search. Ignored if PostgreSQL or Sphinx are enabled. Can either
|
|
||||||
be 'fulltext' or 'like' (default). The former is faster and more efficient
|
|
||||||
but requires the lame old MyISAM engine for MySQL. The latter
|
|
||||||
will work with InnoDB but could be miserably slow on large
|
|
||||||
systems. We'll probably add another type sometime in the future,
|
|
||||||
with our own indexing system (maybe like MediaWiki's).
|
|
||||||
|
|
||||||
sessions
|
|
||||||
--------
|
|
||||||
|
|
||||||
Session handling.
|
|
||||||
|
|
||||||
handle: boolean. Whether we should register our own PHP session-handling
|
|
||||||
code (using the database and cache layers if enabled). Defaults to false.
|
|
||||||
Setting this to true makes some sense on large or multi-server
|
|
||||||
sites, but it probably won't hurt for smaller ones, either.
|
|
||||||
debug: whether to output debugging info for session storage. Can help
|
|
||||||
with weird session bugs, sometimes. Default false.
|
|
||||||
|
|
||||||
ping
|
|
||||||
----
|
|
||||||
|
|
||||||
Using the "XML-RPC Ping" method initiated by weblogs.com, the site can
|
|
||||||
notify third-party servers of updates.
|
|
||||||
|
|
||||||
notify: an array of URLs for ping endpoints. Default is the empty
|
|
||||||
array (no notification).
|
|
||||||
|
|
||||||
notice
|
|
||||||
------
|
|
||||||
|
|
||||||
Configuration options specific to notices.
|
|
||||||
|
|
||||||
contentlimit: max length of the plain-text content of a notice.
|
|
||||||
Default is null, meaning to use the site-wide text limit.
|
|
||||||
0 means no limit.
|
|
||||||
defaultscope: default scope for notices. If null, the default
|
|
||||||
scope depends on site/private. It's 1 if the site is private,
|
|
||||||
0 otherwise. Set this value to override.
|
|
||||||
|
|
||||||
message
|
|
||||||
-------
|
|
||||||
|
|
||||||
Configuration options specific to messages.
|
|
||||||
|
|
||||||
contentlimit: max length of the plain-text content of a message.
|
|
||||||
Default is null, meaning to use the site-wide text limit.
|
|
||||||
0 means no limit.
|
|
||||||
|
|
||||||
logincommand
|
|
||||||
------------
|
|
||||||
|
|
||||||
Configuration options for the login command.
|
|
||||||
|
|
||||||
disabled: whether to enable this command. If enabled, users who send
|
|
||||||
the text 'login' to the site through any channel will
|
|
||||||
receive a link to login to the site automatically in return.
|
|
||||||
Possibly useful for users who primarily use an XMPP or SMS
|
|
||||||
interface and can't be bothered to remember their site
|
|
||||||
password. Note that the security implications of this are
|
|
||||||
pretty serious and have not been thoroughly tested. You
|
|
||||||
should enable it only after you've convinced yourself that
|
|
||||||
it is safe. Default is 'false'.
|
|
||||||
|
|
||||||
singleuser
|
|
||||||
----------
|
|
||||||
|
|
||||||
If an installation has only one user, this can simplify a lot of the
|
|
||||||
interface. It also makes the user's profile the root URL.
|
|
||||||
|
|
||||||
enabled: Whether to run in "single user mode". Default false.
|
|
||||||
nickname: nickname of the single user. If no nickname is specified,
|
|
||||||
the site owner account will be used (if present).
|
|
||||||
|
|
||||||
robotstxt
|
|
||||||
---------
|
|
||||||
|
|
||||||
We put out a default robots.txt file to guide the processing of
|
|
||||||
Web crawlers. See http://www.robotstxt.org/ for more information
|
|
||||||
on the format of this file.
|
|
||||||
|
|
||||||
crawldelay: if non-empty, this value is provided as the Crawl-Delay:
|
|
||||||
for the robots.txt file. see http://ur1.ca/l5a0
|
|
||||||
for more information. Default is zero, no explicit delay.
|
|
||||||
disallow: Array of (virtual) directories to disallow. Default is 'main',
|
|
||||||
'search', 'message', 'settings', 'admin'. Ignored when site
|
|
||||||
is private, in which case the entire site ('/') is disallowed.
|
|
||||||
|
|
||||||
api
|
|
||||||
---
|
|
||||||
|
|
||||||
Options for the Twitter-like API.
|
|
||||||
|
|
||||||
realm: HTTP Basic Auth realm (see http://tools.ietf.org/html/rfc2617
|
|
||||||
for details). Some third-party tools like ping.fm want this to be
|
|
||||||
'Identi.ca API', so set it to that if you want to. default = null,
|
|
||||||
meaning 'something based on the site name'.
|
|
||||||
|
|
||||||
nofollow
|
|
||||||
--------
|
|
||||||
|
|
||||||
We optionally put 'rel="nofollow"' on some links in some pages. The
|
|
||||||
following configuration settings let you fine-tune how or when things
|
|
||||||
are nofollowed. See http://en.wikipedia.org/wiki/Nofollow for more
|
|
||||||
information on what 'nofollow' means.
|
|
||||||
|
|
||||||
subscribers: whether to nofollow links to subscribers on the profile
|
|
||||||
and personal pages. Default is true.
|
|
||||||
members: links to members on the group page. Default true.
|
|
||||||
peopletag: links to people listed in the peopletag page. Default true.
|
|
||||||
external: external links in notices. One of three values: 'sometimes',
|
|
||||||
'always', 'never'. If 'sometimes', then external links are not
|
|
||||||
nofollowed on profile, notice, and favorites page. Default is
|
|
||||||
'sometimes'.
|
|
||||||
|
|
||||||
url
|
|
||||||
---
|
|
||||||
|
|
||||||
These are some options for fine-tuning how and when the server will
|
|
||||||
shorten URLs.
|
|
||||||
|
|
||||||
shortener: URL shortening service to use by default. Users can override
|
|
||||||
individually. 'internal' by default.
|
|
||||||
maxurllength: If an URL is strictly longer than this limit, it will be
|
|
||||||
shortened. Note that the URL shortener service may return an
|
|
||||||
URL longer than this limit. Defaults to 100. Users can
|
|
||||||
override. If set to 0, all URLs will be shortened.
|
|
||||||
maxnoticelength: If a notice is strictly longer than this limit, all
|
|
||||||
URLs in the notice will be shortened. Users can override.
|
|
||||||
-1 means the text limit for notices.
|
|
||||||
|
|
||||||
router
|
|
||||||
------
|
|
||||||
|
|
||||||
We use a router class for mapping URLs to code. This section controls
|
|
||||||
how that router works.
|
|
||||||
|
|
||||||
cache: whether to cache the router in cache layers. Defaults to true,
|
|
||||||
but may be set to false for developers (who might be actively
|
|
||||||
adding pages, so won't want the router cached) or others who see
|
|
||||||
strange behavior. You're unlikely to need this unless developing..
|
|
||||||
|
|
||||||
http
|
|
||||||
----
|
|
||||||
|
|
||||||
Settings for the HTTP client.
|
|
||||||
|
|
||||||
ssl_cafile: location of the CA file for SSL. If not set, won't verify
|
|
||||||
SSL peers. Default unset.
|
|
||||||
curl: Use cURL <http://curl.haxx.se/> for doing HTTP calls. You must
|
|
||||||
have the PHP curl extension installed for this to work.
|
|
||||||
proxy_host: Host to use for proxying HTTP requests. If unset, doesn't
|
|
||||||
do any HTTP proxy stuff. Default unset.
|
|
||||||
proxy_port: Port to use to connect to HTTP proxy host. Default null.
|
|
||||||
proxy_user: Username to use for authenticating to the HTTP proxy. Default null.
|
|
||||||
proxy_password: Password to use for authenticating to the HTTP proxy. Default null.
|
|
||||||
proxy_auth_scheme: Scheme to use for authenticating to the HTTP proxy. Default null.
|
|
||||||
|
|
||||||
plugins
|
|
||||||
-------
|
|
||||||
|
|
||||||
default: associative array mapping plugin name to array of arguments. To disable
|
|
||||||
a default plugin, unset its value in this array.
|
|
||||||
locale_path: path for finding plugin locale files. In the plugin's directory
|
|
||||||
by default.
|
|
||||||
server: Server to find static files for a plugin when the page is plain old HTTP.
|
|
||||||
Defaults to site/server (same as pages). Use this to move plugin CSS and
|
|
||||||
JS files to a CDN.
|
|
||||||
sslserver: Server to find static files for a plugin when the page is HTTPS. Defaults
|
|
||||||
to site/server (same as pages). Use this to move plugin CSS and JS files
|
|
||||||
to a CDN.
|
|
||||||
path: Path to the plugin files. defaults to site/path + '/plugins/'. Expects that
|
|
||||||
each plugin will have a subdirectory at plugins/NameOfPlugin. Change this
|
|
||||||
if you're using a CDN.
|
|
||||||
sslpath: Path to use on the SSL server. Same as plugins/path.
|
|
||||||
|
|
||||||
performance
|
|
||||||
-----------
|
|
||||||
|
|
||||||
high: if you need high performance, or if you're seeing bad
|
|
||||||
performance, set this to true. It will turn off some high-intensity code from
|
|
||||||
the site.
|
|
||||||
|
|
||||||
oldschool
|
|
||||||
---------
|
|
||||||
|
|
||||||
enabled: enable certain old-style user settings options, like stream-only mode,
|
|
||||||
conversation trees, and nicknames in streams. Off by default, and
|
|
||||||
may not be well supported in future versions.
|
|
||||||
|
|
||||||
|
|
1
CONTRIBUTING.md
Normal file
1
CONTRIBUTING.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
GNU social's contributing resources and instructions are made available at [DOCUMENTATION/DEVELOPERS](https://notabug.org/diogo/gnu-social/src/nightly/DOCUMENTATION/DEVELOPERS).
|
99
CREDITS.md
Normal file
99
CREDITS.md
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
Credits for GNU social
|
||||||
|
======================
|
||||||
|
The following is an incomplete list of developers
|
||||||
|
who've worked on GNU social, or its predecessors
|
||||||
|
StatusNet and Free Social. Apologies for any
|
||||||
|
oversight; please let mattl@gnu.org know if
|
||||||
|
anyone's been overlooked in error.
|
||||||
|
|
||||||
|
Current team
|
||||||
|
------------
|
||||||
|
* Matt Lee
|
||||||
|
* Mikael Nordfeldth
|
||||||
|
* Diogo Cordeiro
|
||||||
|
* Bruno Casteleiro
|
||||||
|
* Miguel Dantas
|
||||||
|
* Alexei Sorokin
|
||||||
|
|
||||||
|
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
|
||||||
|
* Bob Mottram
|
||||||
|
* David Yip
|
||||||
|
* Neil E Hodges
|
||||||
|
* Moonman
|
||||||
|
* Normandy
|
||||||
|
* Verius
|
||||||
|
* Alexei Sorokin
|
||||||
|
* Daniel Supernault
|
||||||
|
|
||||||
|
Credits for StatusNet
|
||||||
|
--------------
|
||||||
|
Leads
|
||||||
|
* Evan Prodromou
|
||||||
|
* 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
|
||||||
|
* Joshua Judson Rosen (rozzin)
|
||||||
|
|
||||||
|
Translators
|
||||||
|
-----------
|
||||||
|
* Siebrand Mazeland
|
||||||
|
* Tiago 'gouki' Faria
|
||||||
|
* TranslateWiki.net
|
||||||
|
|
||||||
|
A special thanks to the thousands of people who
|
||||||
|
have tried out GNU social, told their friends, and
|
||||||
|
built the fediverse network to what it is today.
|
||||||
|
|
||||||
|
License help from
|
||||||
|
-----------------
|
||||||
|
* Bradley M. Kuhn
|
61
DOCUMENTATION/DEVELOPERS/CONTRIBUTING/boilerplate.php
Normal file
61
DOCUMENTATION/DEVELOPERS/CONTRIBUTING/boilerplate.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?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.';
|
||||||
|
}
|
||||||
|
}
|
275
DOCUMENTATION/DEVELOPERS/CONTRIBUTING/coding_standards.md
Normal file
275
DOCUMENTATION/DEVELOPERS/CONTRIBUTING/coding_standards.md
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
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.
|
@@ -0,0 +1,32 @@
|
|||||||
|
Submission Checklist
|
||||||
|
================================================================================
|
||||||
|
This document serves as a handy checklist for submitted merges and patches to
|
||||||
|
the GNU social 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.
|
@@ -42,11 +42,10 @@ EndShowUAStyles: End showing custom User-Agent links; good place to add user-age
|
|||||||
StartShowScripts: Showing JavaScript links
|
StartShowScripts: Showing JavaScript links
|
||||||
- $action: the current action
|
- $action: the current action
|
||||||
|
|
||||||
EndShowScripts: End showing JavaScript links; good place to add custom
|
EndShowScripts: End showing JavaScript links; good place to add custom links
|
||||||
links like Google Analytics
|
|
||||||
- $action: the current action
|
- $action: the current action
|
||||||
|
|
||||||
StartShowJQueryScripts: Showing JQuery script links (use this to link to e.g. Google mirrors)
|
StartShowJQueryScripts: Showing JQuery script links
|
||||||
- $action: the current action
|
- $action: the current action
|
||||||
|
|
||||||
EndShowJQueryScripts: End showing JQuery script links
|
EndShowJQueryScripts: End showing JQuery script links
|
||||||
@@ -1431,7 +1430,7 @@ StartNoticeListPrefill: Before pre-filling a list of notices with extra data
|
|||||||
|
|
||||||
EndNoticeListPrefill: After pre-filling a list of notices with extra data
|
EndNoticeListPrefill: After pre-filling a list of notices with extra data
|
||||||
- &$notices: Notices that were pre-filled
|
- &$notices: Notices that were pre-filled
|
||||||
- &$profiles: Profiles that were pre-filled
|
- &$profiles: Profiles that were pre-filled
|
||||||
- $avatarSize: The avatar size for the list
|
- $avatarSize: The avatar size for the list
|
||||||
|
|
||||||
OtherAccountProfiles: Hook to add account profiles to a user account profile block
|
OtherAccountProfiles: Hook to add account profiles to a user account profile block
|
@@ -77,7 +77,7 @@ Plugins are configured using public instance attributes. To set their values,
|
|||||||
site administrators use this syntax:
|
site administrators use this syntax:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
addPlugin('Sample', array('attr1' => 'foo', 'attr2' => 'bar'));
|
addPlugin('Sample', ('attr1' => 'foo', 'attr2' => 'bar'));
|
||||||
```
|
```
|
||||||
|
|
||||||
The same plugin class can be initialized multiple times with different arguments:
|
The same plugin class can be initialized multiple times with different arguments:
|
||||||
@@ -260,11 +260,11 @@ Take arguments for running
|
|||||||
This method is called first, and it lets the action class get all its arguments
|
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.
|
and validate them. It's also the time to fetch any relevant data from the database.
|
||||||
|
|
||||||
Action classes should run parent::prepare($args) as the first line of this
|
Action classes should run parent::prepare(array $args = []) as the first line
|
||||||
method to make sure the default argument-processing happens.
|
of this method to make sure the default argument-processing happens.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
function prepare($args)
|
function prepare(array $args = [])
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -286,9 +286,9 @@ should be done in the prepare() method; by the time handle() is called the
|
|||||||
action should be more or less ready to go.
|
action should be more or less ready to go.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
112
DOCUMENTATION/DEVELOPERS/README.md
Normal file
112
DOCUMENTATION/DEVELOPERS/README.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# 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. Run php-cs-fixer. We also recommend you to use tools like phpstan, phpactor, phpcs and phpmd
|
||||||
|
2. Run our unit tests (`./vendor/bin/phpunit --testsuite Core`)
|
||||||
|
3. Respect our [VERSIONING](https://notabug.org/diogo/gnu-social/src/nightly/DOCUMENTATION/VERSIONING.md) system
|
||||||
|
4. You may merge the Merge 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!
|
972
DOCUMENTATION/SYSTEM_ADMINISTRATORS/CONFIGURE.md
Normal file
972
DOCUMENTATION/SYSTEM_ADMINISTRATORS/CONFIGURE.md
Normal file
@@ -0,0 +1,972 @@
|
|||||||
|
Configuration options
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
The main configuration file for GNU social (excepting configurations for
|
||||||
|
dependency software) is config.php in your GNU social directory. If you edit any
|
||||||
|
other file in the directory, like `lib/default.php` (where most of the defaults
|
||||||
|
are defined), you will lose your configuration options in any upgrade, and you
|
||||||
|
will wish that you had been more careful.
|
||||||
|
|
||||||
|
Starting with version 0.9.0, a Web based configuration panel has been added to
|
||||||
|
GNU social. The preferred method for changing config options is to use this
|
||||||
|
panel.
|
||||||
|
|
||||||
|
A command-line script, setconfig.php, can be used to set individual
|
||||||
|
configuration options. It's in the scripts/ directory.
|
||||||
|
|
||||||
|
Starting with version 0.7.1, you can put config files in the /etc/GNU social/
|
||||||
|
directory on your server, if it exists. Config files will be included in this
|
||||||
|
order:
|
||||||
|
|
||||||
|
* `/etc/GNU social/statusnet.php` - server-wide config
|
||||||
|
|
||||||
|
* `/etc/GNU social/<servername>.php` - for a virtual host
|
||||||
|
|
||||||
|
* `/etc/GNU social/<servername>_<pathname>.php` - for a path
|
||||||
|
|
||||||
|
* `INSTALLDIR/config.php` - for a particular implementation
|
||||||
|
|
||||||
|
Almost all configuration options are made through a two-dimensional
|
||||||
|
associative array, cleverly named $config. A typical configuration
|
||||||
|
line will be:
|
||||||
|
|
||||||
|
$config['section']['option'] = value;
|
||||||
|
|
||||||
|
For brevity, the following documentation describes each section and
|
||||||
|
option.
|
||||||
|
|
||||||
|
|
||||||
|
site
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This section is a catch-all for site-wide variables.
|
||||||
|
|
||||||
|
* `name` (string, required, default "Another GNU social Instance"): the name of
|
||||||
|
your site, like 'YourCompany Microblog'.
|
||||||
|
|
||||||
|
* `server` (string, required, default null): the server part of your site's URLs,
|
||||||
|
like 'example.net'.
|
||||||
|
|
||||||
|
* `path` (string, required, default ''): The path part of your site's URLs, like
|
||||||
|
'statusnet' or '' (installed in root).
|
||||||
|
|
||||||
|
* `fancy` (string, default false): whether or not your site uses fancy URLs (see Fancy URLs
|
||||||
|
section above).
|
||||||
|
|
||||||
|
* `logfile` (string, default './'): full path to a file for GNU social to save
|
||||||
|
logging information to. You may want to use this if you don't have access
|
||||||
|
to syslog.
|
||||||
|
|
||||||
|
* `logdebug` (boolean, default false): whether to log additional debug info like
|
||||||
|
backtraces on hard errors.
|
||||||
|
|
||||||
|
* `locale_path` (string, default null): full path to the directory for locale
|
||||||
|
data. Unless you store all your locale data in one place, you probably
|
||||||
|
don't need to use this.
|
||||||
|
|
||||||
|
* `language` (string, default "en_us"): default language for your site. Defaults
|
||||||
|
to US English. Note that this is overridden if a user is logged in and has
|
||||||
|
selected a different language. It is also overridden if the user is NOT
|
||||||
|
logged in, but their browser requests a different langauge. Since pretty
|
||||||
|
much everybody's browser requests a language, that means that changing
|
||||||
|
this setting has little or no effect in practice.
|
||||||
|
|
||||||
|
* `languages` (array, default null): A list of languages supported on your site.
|
||||||
|
Typically you'd only change this if you wanted to disable support for one or
|
||||||
|
another language:
|
||||||
|
|
||||||
|
"unset($config['site']['languages']['de'])" will disable
|
||||||
|
support for German.
|
||||||
|
|
||||||
|
* `theme` (string, default 'default'): Theme for your site (see Theme section).
|
||||||
|
Two themes are provided by default: 'default' and 'stoica' (the one used by
|
||||||
|
Identi.ca). It's appreciated if you don't use the 'stoica' theme except as
|
||||||
|
the basis for your own.
|
||||||
|
|
||||||
|
* `email` (string, required): contact email address for your site. By default,
|
||||||
|
it's extracted from your Web server environment; you may want to customize it.
|
||||||
|
|
||||||
|
* `broughtbyurl` (string, default null): name of an organization or individual
|
||||||
|
who provides the service. Each page will include a link to this name in the
|
||||||
|
footer. A good way to link to the blog, forum, wiki, corporate portal, or
|
||||||
|
whoever is making the service available.
|
||||||
|
|
||||||
|
* `broughtby` (string, default null): text used for the "brought by" link.
|
||||||
|
|
||||||
|
* `timezone` (string, default 'UTC'): default timezone for message display. Users
|
||||||
|
can set their own time zone. Defaults to 'UTC', which is a pretty good
|
||||||
|
default.
|
||||||
|
|
||||||
|
* `closed` (boolean, default false): If set to 'true', will disallow registration
|
||||||
|
on your site. This is a cheap way to restrict accounts to only one
|
||||||
|
individual or group; just register the accounts you want on the service,
|
||||||
|
*then* set this variable to 'true'.
|
||||||
|
|
||||||
|
* `inviteonly` (boolean, default false): If set to 'true', will only allow
|
||||||
|
registration if the user was invited by an existing user.
|
||||||
|
|
||||||
|
* `private` (boolean, default false): If set to 'true', anonymous users will be
|
||||||
|
redirected to the 'login' page. Also, API methods that normally require no
|
||||||
|
authentication will require it. Note that this does not turn off
|
||||||
|
registration; use 'closed' or 'inviteonly' for the behaviour you want.
|
||||||
|
|
||||||
|
* `notice` (string, default null): A plain string that will appear on every
|
||||||
|
page. A good place to put introductory information about your service, or
|
||||||
|
info about upgrades and outages, or other community info. Any HTML will be
|
||||||
|
escaped.
|
||||||
|
|
||||||
|
* `logo` (string, default null): URL of an image file to use as the logo for the
|
||||||
|
site. Overrides the logo in the theme, if any.
|
||||||
|
|
||||||
|
* `ssllogo` (string, default null): URL of an image file to use as the logo on
|
||||||
|
SSL pages. If unset, theme logo is used instead.
|
||||||
|
|
||||||
|
* `ssl` (enum['always','sometimes','never'], default 'never'): Whether to use SSL
|
||||||
|
and https:// URLs for some or all pages.
|
||||||
|
|
||||||
|
Possible values are 'always' (use it for all pages), 'never' (don't use it
|
||||||
|
for any pages), or 'sometimes' (use it for sensitive pages that include
|
||||||
|
passwords like login and registration, but not for regular pages).
|
||||||
|
|
||||||
|
* `sslproxy` (boolean, default false): Whether to force GNUsocial to think it
|
||||||
|
is HTTPS when the server gives no such information. I.e. when you're using
|
||||||
|
a reverse proxy that adds the encryption layer but the webserver that runs
|
||||||
|
PHP isn't configured with a key and certificate.
|
||||||
|
|
||||||
|
* `sslserver` (string, default null): use an alternate server name for SSL URLs,
|
||||||
|
like 'secure.example.org'. You should be careful to set cookie parameters
|
||||||
|
correctly so that both the SSL server and the "normal" server can access
|
||||||
|
the session cookie and preferably other cookies as well.
|
||||||
|
|
||||||
|
* `dupelimit` (integer, default 60): minimum time allowed for one person to say
|
||||||
|
the same thing twice. Default 60s. Anything lower is considered a user or
|
||||||
|
UI error.
|
||||||
|
|
||||||
|
* `textlimit` (integer, default 0): default max size for texts in the site. Can
|
||||||
|
be fine-tuned for notices, messages, profile bios and group descriptions.
|
||||||
|
Zero indicates no limit.
|
||||||
|
|
||||||
|
* favicon: the path to a custom favicon, eg: favicon.png
|
||||||
|
|
||||||
|
* `x-static-delivery` (string, default null): when a string, use this
|
||||||
|
as the header with wich to serve static files. Possible values are
|
||||||
|
'X-Sendfile' (for Apache and others) and 'X-Accel-Redirect' (for
|
||||||
|
nginx).
|
||||||
|
|
||||||
|
|
||||||
|
db
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This section is a reference to the configuration options for
|
||||||
|
`DB_DataObject` (see
|
||||||
|
<http://pear.php.net/manual/en/package.database.db-dataobject.intro-configuration.php>).
|
||||||
|
The ones that you may want to set are listed below for clarity.
|
||||||
|
|
||||||
|
* `database` (string, required, default null): a DSN (Data Source Name) for your
|
||||||
|
GNU social database. This is in the format
|
||||||
|
'protocol://username:password@hostname/databasename', where 'protocol' is '
|
||||||
|
mysql' or 'mysqli' (or possibly 'postgresql', if you really know what
|
||||||
|
you're doing), 'username' is the username, 'password' is the password,
|
||||||
|
and etc.
|
||||||
|
|
||||||
|
* `ini_yourdbname` (string, default null): if your database is not named 'statusnet',
|
||||||
|
you'll need to set this to point to the location of the statusnet.ini file.
|
||||||
|
Note that the real name of your database should go in there, not literally
|
||||||
|
'yourdbname'.
|
||||||
|
|
||||||
|
* `db_driver`(enum['DB','MDB2'], default null): You can try changing this to
|
||||||
|
'MDB2' to use the other driver type for DB_DataObject, but note that it
|
||||||
|
breaks the OpenID libraries, which only support PEAR::DB.
|
||||||
|
|
||||||
|
* `quote_identifiers`(boolean, default false): Set this to true if you're using
|
||||||
|
postgresql.
|
||||||
|
|
||||||
|
* `type` (enum["mysql", "postgresql"], default 'mysql'): Used for certain
|
||||||
|
database-specific optimization code. Assumes mysql if not set. MySQL also
|
||||||
|
covers MySQLi and MariaDB.
|
||||||
|
|
||||||
|
* `mirror` (array, default null): you can set this to an array of DSNs, in the
|
||||||
|
format of the above 'database' value. If it's set, certain read-only
|
||||||
|
actions will use a random value out of this array for the database, rather
|
||||||
|
than the one in 'database' (actually, 'database' is overwritten). You can
|
||||||
|
offload a busy DB server by setting up MySQL replication and adding the
|
||||||
|
slaves to this array. Note that if you want some requests to go to the
|
||||||
|
'database' (master) server, you'll need to include it in this array, too.
|
||||||
|
|
||||||
|
* `utf8` (boolean, true): whether to talk to the database in UTF-8 mode. This is
|
||||||
|
the default with new installations, but older sites may want to turn it off
|
||||||
|
until they get their databases fixed up. See "UTF-8 database" above for
|
||||||
|
details.
|
||||||
|
|
||||||
|
* `schemacheck` (enum["runtime", "script"], default "runtime"): when
|
||||||
|
to let plugins check the database schema to add tables or update
|
||||||
|
them. 'runtime' can be costly (plugins check the schema on every
|
||||||
|
hit, adding potentially several db queries, some quite long), but
|
||||||
|
not everyone knows how to run a script or has the access in their
|
||||||
|
hosting environment to do so. If you can, set this to 'script' and
|
||||||
|
run scripts/checkschema.php whenever you install or upgrade a
|
||||||
|
plugin.
|
||||||
|
|
||||||
|
|
||||||
|
syslog
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
By default, GNU social sites log error messages to the syslog facility.
|
||||||
|
(You can override this using the 'logfile' parameter described above).
|
||||||
|
|
||||||
|
* `appname` (string, default `'GNU social'`): The name that GNU social uses to log
|
||||||
|
messages. By default it's "GNU social", but if you have more than one
|
||||||
|
installation on the server, you may want to change the name for each
|
||||||
|
instance so you can track log messages more easily.
|
||||||
|
|
||||||
|
* `facility` (string, default `'LOG_USER'`): what syslog facility to use. Only set
|
||||||
|
this if you know what syslog is and have a good reason to change it.
|
||||||
|
|
||||||
|
|
||||||
|
queue
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
You can configure the software to queue time-consuming tasks, like
|
||||||
|
sending out SMS email or XMPP messages, for off-line processing. See
|
||||||
|
'Queues and daemons' above for how to set this up.
|
||||||
|
|
||||||
|
* `enabled` (boolean, default false): Whether to uses queues.
|
||||||
|
|
||||||
|
* `daemon` (boolean, default false): Wather to use queuedaemon. False means
|
||||||
|
you'll use OpportunisticQM plugin.
|
||||||
|
|
||||||
|
* `subsystem` (enum["db", "stomp"], default 'db'): Which kind of queueserver to
|
||||||
|
use. Values include "db" for our hacked-together database queuing (no
|
||||||
|
other server required), "stomp" for a stomp server, and "redis" for a Redis
|
||||||
|
server.
|
||||||
|
|
||||||
|
* `threads` (int): How many queue "threads" (actually processes) to run. Defaults to
|
||||||
|
number of cpu cores in unix-like systems or 1 on other OSes.
|
||||||
|
|
||||||
|
* `items_to_handle` (int): How many items to handle before a daemon process exits.
|
||||||
|
Default to unlimited.
|
||||||
|
|
||||||
|
* `stomp_server` (string, default null): "broker URI" for stomp server.
|
||||||
|
Something like "tcp://hostname:61613". More complicated ones are possible;
|
||||||
|
see your stomp server's documentation for details.
|
||||||
|
|
||||||
|
* `queue_basename` (string, default null): a root name to use for queues (stomp
|
||||||
|
only). Typically something like '/queue/sitename/' makes sense. If running
|
||||||
|
multiple instances on the same server, make sure that either this setting
|
||||||
|
or $config['site']['nickname'] are unique for each site to keep them
|
||||||
|
separate.
|
||||||
|
|
||||||
|
* `stomp_username` (string, default null): username for connecting to the stomp
|
||||||
|
server.
|
||||||
|
|
||||||
|
* `stomp_password` (string, default null): password for connecting to the stomp
|
||||||
|
server.
|
||||||
|
|
||||||
|
* `stomp_persistent` (boolean, default true): Keep items across queue server
|
||||||
|
restart, if enabled. Note: Under ActiveMQ, the server configuration
|
||||||
|
determines if and how persistent storage is actually saved.
|
||||||
|
|
||||||
|
If using a message queue server other than ActiveMQ, you may
|
||||||
|
need to disable this if it does not support persistence.
|
||||||
|
|
||||||
|
* `stomp_transactions` (boolean, default true): use transactions to aid in error
|
||||||
|
detection. A broken transaction will be seen quickly, allowing a message to
|
||||||
|
be redelivered immediately if a daemon crashes.
|
||||||
|
|
||||||
|
If using a message queue server other than ActiveMQ, you may need to
|
||||||
|
disable this if it does not support transactions.
|
||||||
|
|
||||||
|
* `stomp_acks` (boolean, default true): send acknowledgements to aid in flow
|
||||||
|
control. An acknowledgement of successful processing tells the server we're
|
||||||
|
ready for more and can help keep things moving smoothly.
|
||||||
|
|
||||||
|
This should *not* be turned off when running with ActiveMQ, (it breaks if
|
||||||
|
you do), but if using another message queue server that does not support
|
||||||
|
acknowledgements you might need to disable this.
|
||||||
|
|
||||||
|
* `softlimit` (integer): an absolute or relative "soft memory limit"; daemons
|
||||||
|
will restart themselves gracefully when they find they've hit this amount
|
||||||
|
of memory usage. Defaults to 90% of PHP's global memory_limit setting.
|
||||||
|
|
||||||
|
* `inboxes` (boolean, default true): delivery of messages to receiver's inboxes
|
||||||
|
can be delayed to queue time for best interactive performance on the
|
||||||
|
sender. This may however be annoyingly slow when using the DB queues, so
|
||||||
|
you can set this to false if it's causing trouble.
|
||||||
|
|
||||||
|
* `breakout` (array, default null): for stomp, individual queues are by default
|
||||||
|
grouped up for best scalability. If some need to be run by separate daemons,
|
||||||
|
etc they can be manually adjusted here.
|
||||||
|
|
||||||
|
Default will share all queues for all sites within each group.
|
||||||
|
Specify as <group>/<queue> or <group>/<queue>/<site>,
|
||||||
|
using nickname identifier as site.
|
||||||
|
|
||||||
|
'main/distrib' separate "distrib" queue covering all sites
|
||||||
|
'xmpp/xmppout/mysite' separate "xmppout" queue covering just 'mysite'
|
||||||
|
|
||||||
|
* `max_retries` (integer, default 10): for stomp, drop messages after N failed
|
||||||
|
attempts to process.
|
||||||
|
|
||||||
|
* `dead_letter_dir` (string, default null): for stomp, optional directory to dump
|
||||||
|
data on failed queue processing events after discarding them.
|
||||||
|
|
||||||
|
* `stomp_no_transactions` (boolean, default false): for stomp, the server does
|
||||||
|
not support transactions, so do not try to user them. This is needed for
|
||||||
|
http://www.morbidq.com/
|
||||||
|
|
||||||
|
* `stomp_no_acks` (boolean, default false): for stomp, the server does not
|
||||||
|
support acknowledgements so do not try to user them. This is needed for
|
||||||
|
http://www.morbidq.com/.
|
||||||
|
|
||||||
|
|
||||||
|
license
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The default license to use for your users notices. The default is the
|
||||||
|
Creative Commons Attribution 3.0 license, which is probably the right
|
||||||
|
choice for any public site. Note that some other servers will not
|
||||||
|
accept notices if you apply a stricter license than this.
|
||||||
|
|
||||||
|
As of 2016, this is largely disregarded in the Fediverse -mb
|
||||||
|
|
||||||
|
* `type` (enum["cc", "allrightsreserved", "private"], default 'cc'): one of
|
||||||
|
'cc' (for Creative Commons licenses), 'allrightsreserved' (default
|
||||||
|
copyright), or 'private' (for private and confidential information).
|
||||||
|
|
||||||
|
* `owner` (string, default 'contributors'): for 'allrightsreserved' or
|
||||||
|
'private', an assigned copyright holder (for example, an employer for a
|
||||||
|
private site).
|
||||||
|
|
||||||
|
* `url` (string, default null): URL of the license, used for links.
|
||||||
|
|
||||||
|
* `title` (string, default null): Title for the license, like 'Creative Commons
|
||||||
|
Attribution 3.0'.
|
||||||
|
|
||||||
|
* `image` (string, default null): URL of a button shown on each page for the
|
||||||
|
license.
|
||||||
|
|
||||||
|
|
||||||
|
mail
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This is for configuring out-going email. We use PEAR's Mail module,
|
||||||
|
see: http://pear.php.net/manual/en/package.mail.mail.factory.php
|
||||||
|
|
||||||
|
* `backend` (enum["mail", "sendmail", "smtp"], default 'mail'): The backend to
|
||||||
|
use for mail. While this defaults to PEAR mail, we recommend SMTP where your
|
||||||
|
setup supports it as it is of the three the more difficult one for script
|
||||||
|
exploits to abuse (relatively speaking - they all have potential problems.)
|
||||||
|
|
||||||
|
* `params` (array, default null): if the mail backend requires any parameters,
|
||||||
|
you can provide them in an associative array.
|
||||||
|
|
||||||
|
* `templates_path` (string, default null): alias for `site->mail_path`
|
||||||
|
|
||||||
|
|
||||||
|
nickname
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This is for configuring nicknames in the service.
|
||||||
|
|
||||||
|
* `blacklist` (array, default null): an array of strings for usernames that
|
||||||
|
may not be registered. A hard-coded default array exists for strings that
|
||||||
|
are used by GNU social (e.g. 'doc', 'main', 'avatar', 'theme') but you may
|
||||||
|
want to add others if you have other software installed in a subdirectory
|
||||||
|
of GNU social or if you just don't want certain words used as usernames.
|
||||||
|
|
||||||
|
* `featured` (array, default null): an array of nicknames of 'featured' users of
|
||||||
|
the site. Can be useful to draw attention to well-known users, or
|
||||||
|
interesting people, or whatever.
|
||||||
|
|
||||||
|
|
||||||
|
avatar
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For configuring avatar access.
|
||||||
|
|
||||||
|
* `dir` (string, default './avatar'): Directory to look for avatar files and to
|
||||||
|
put them into. Defaults to avatar subdirectory of install directory; if
|
||||||
|
you change it, make sure to change path, too.
|
||||||
|
|
||||||
|
* `path` (string, 'default './avatar'): Path to avatars. Defaults to path for
|
||||||
|
avatar subdirectory, but you can change it if you wish. Note that this will
|
||||||
|
be included with the avatar server, too.
|
||||||
|
|
||||||
|
* `server` (string, default null): If set, defines another server where avatars
|
||||||
|
are stored in the root directory. Note that the 'avatar' subdir still has
|
||||||
|
to be writeable. You'd typically use this to split HTTP requests on the
|
||||||
|
client to speed up page loading, either with another virtual server or
|
||||||
|
with an NFS or SAMBA share. Clients typically only make 2 connections to a
|
||||||
|
single server at a time
|
||||||
|
<https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4>,
|
||||||
|
so this can parallelize the job.
|
||||||
|
|
||||||
|
* `ssl` (boolean, default null): Whether to access avatars using HTTPS. Defaults
|
||||||
|
to null, meaning to guess based on site-wide SSL settings.
|
||||||
|
|
||||||
|
|
||||||
|
public
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For configuring the public stream.
|
||||||
|
|
||||||
|
* `localonly` (boolean, default true): If set to true, only messages posted by
|
||||||
|
users of this service (rather than other services, filtered through
|
||||||
|
OStatus) are shown in the public stream. Default true.
|
||||||
|
|
||||||
|
* `blacklist` (array, default null): An array of IDs of users to hide from the
|
||||||
|
public stream. Useful if you have someone making excessive Twitterfeed
|
||||||
|
posts to the site, other kinds of automated posts, testing bots, etc.
|
||||||
|
|
||||||
|
* `autosource` (array, default null): Sources of notices that are from automatic
|
||||||
|
posters, and thus should be kept off the public timeline.
|
||||||
|
|
||||||
|
|
||||||
|
theme
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
* `server` (string, default null): Like avatars, you can speed up page loading
|
||||||
|
by pointing the theme file lookup to another server (virtual or real).
|
||||||
|
The default of null will use the same server as PA.
|
||||||
|
|
||||||
|
* `dir` (string, default "./themes"): Directory where theme files are stored.
|
||||||
|
Used to determine whether to show parts of a theme file. Defaults to the
|
||||||
|
theme subdirectory of the install directory.
|
||||||
|
|
||||||
|
* `path` (string, default null): Path part of theme URLs, before the theme name. Relative to the
|
||||||
|
theme server. It may make sense to change this path when upgrading,
|
||||||
|
(using version numbers as the path) to make sure that all files are
|
||||||
|
reloaded by caching clients or proxies. Defaults to null,
|
||||||
|
which means to use the site path + '/theme'.
|
||||||
|
|
||||||
|
* `ssl` (boolean, default null): Whether to use SSL for theme elements. Default
|
||||||
|
is null, which means guess based on site SSL settings.
|
||||||
|
|
||||||
|
* `sslserver` (string, default null): SSL server to use when page is
|
||||||
|
HTTPS-encrypted. If unspecified, site ssl server and so on will be used.
|
||||||
|
|
||||||
|
* `sslpath` (string, default null): If sslserver if defined, path to use when
|
||||||
|
page is HTTPS-encrypted.
|
||||||
|
|
||||||
|
|
||||||
|
javascript
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
* `server` (string, default null): You can speed up page loading by pointing the
|
||||||
|
theme file lookup to another server (virtual or real). Defaults to NULL,
|
||||||
|
meaning to use the site server.
|
||||||
|
|
||||||
|
* `path` (string default null): Path part of Javascript URLs. Defaults to null,
|
||||||
|
which means to use the site path + '/js/'.
|
||||||
|
|
||||||
|
* `ssl` (boolean, default null): Whether to use SSL for JavaScript files.
|
||||||
|
Default is null, which means guess based on site SSL settings.
|
||||||
|
|
||||||
|
* `sslserver` (string, default null): SSL server to use when page is HTTPS-
|
||||||
|
encrypted. If unspecified, site ssl server and so on will be used.
|
||||||
|
|
||||||
|
* `sslpath` (string, default null): If sslserver if defined, path to use when
|
||||||
|
page is HTTPS-encrypted.
|
||||||
|
|
||||||
|
* `bustframes` (boolean, default true): If true, all web pages will break out of
|
||||||
|
framesets. If false, can comfortably live in a frame or iframe... probably.
|
||||||
|
|
||||||
|
|
||||||
|
xmpp
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For configuring the XMPP sub-system.
|
||||||
|
|
||||||
|
* `enabled` (boolean, default false): Whether to accept and send messages by
|
||||||
|
XMPP. Default false.
|
||||||
|
|
||||||
|
* `server` (string, default null): Server part of XMPP ID for update user.
|
||||||
|
|
||||||
|
* `port` (integer, default 5222): Connection port for clients.
|
||||||
|
|
||||||
|
* `user` (string, default null): Username for the client connection. Users will
|
||||||
|
receive messages from 'user'@'server'.
|
||||||
|
|
||||||
|
* `resource`: a unique identifier for the connection to the server. This
|
||||||
|
is actually used as a prefix for each XMPP component in the system.
|
||||||
|
|
||||||
|
* `password`: password for the user account.
|
||||||
|
|
||||||
|
* `host`: some XMPP domains are served by machines with a different
|
||||||
|
hostname. Set this to the correct hostname if that's the
|
||||||
|
case with your server.
|
||||||
|
|
||||||
|
* `encryption`: Whether to encrypt the connection between GNU social and the
|
||||||
|
XMPP server. Defaults to true, but you can get
|
||||||
|
considerably better performance turning it off if you're
|
||||||
|
connecting to a server on the same machine or on a
|
||||||
|
protected network.
|
||||||
|
|
||||||
|
* `debug`: if turned on, this will make the XMPP library blurt out all of
|
||||||
|
the incoming and outgoing messages as XML stanzas. Use as a
|
||||||
|
last resort, and never turn it on if you don't have queues
|
||||||
|
enabled, since it will spit out sensitive data to the browser.
|
||||||
|
|
||||||
|
* `public`: an array of JIDs to send _all_ notices to. This is useful for
|
||||||
|
participating in third-party search and archiving services.
|
||||||
|
|
||||||
|
|
||||||
|
invite
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For configuring invites.
|
||||||
|
|
||||||
|
* `enabled`: Whether to allow users to send invites. Default true.
|
||||||
|
|
||||||
|
|
||||||
|
tag
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Miscellaneous tagging stuff.
|
||||||
|
|
||||||
|
* `dropoff`: Decay factor for tag listing, in seconds.
|
||||||
|
Defaults to exponential decay over ten days; you can twiddle
|
||||||
|
with it to try and get better results for your site.
|
||||||
|
|
||||||
|
|
||||||
|
popular
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Settings for the "popular" section of the site.
|
||||||
|
|
||||||
|
* `dropoff`: Decay factor for popularity listing, in seconds.
|
||||||
|
Defaults to exponential decay over ten days; you can twiddle
|
||||||
|
with it to try and get better results for your site.
|
||||||
|
|
||||||
|
|
||||||
|
daemon
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For daemon processes.
|
||||||
|
|
||||||
|
* `piddir`: directory that daemon processes should write their PID file
|
||||||
|
(process ID) to. Defaults to /var/run/, which is where this
|
||||||
|
stuff should usually go on Unix-ish systems.
|
||||||
|
|
||||||
|
* `user`: If set, the daemons will try to change their effective user ID
|
||||||
|
to this user before running. Probably a good idea, especially if
|
||||||
|
you start the daemons as root. Note: user name, like 'daemon',
|
||||||
|
not 1001.
|
||||||
|
|
||||||
|
* `group`: If set, the daemons will try to change their effective group ID
|
||||||
|
to this named group. Again, a name, not a numerical ID.
|
||||||
|
|
||||||
|
|
||||||
|
emailpost
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For post-by-email.
|
||||||
|
|
||||||
|
* `enabled`: Whether to enable post-by-email. Defaults to true. You will
|
||||||
|
also need to set up maildaemon.php.
|
||||||
|
|
||||||
|
|
||||||
|
sms
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For SMS integration.
|
||||||
|
|
||||||
|
* `enabled`: Whether to enable SMS integration. Defaults to true. Queues
|
||||||
|
should also be enabled.
|
||||||
|
|
||||||
|
|
||||||
|
integration
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
A catch-all for integration with other systems.
|
||||||
|
|
||||||
|
* `taguri`: base for tag:// URIs. Defaults to site-server + ',2009'.
|
||||||
|
|
||||||
|
|
||||||
|
inboxes
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For notice inboxes.
|
||||||
|
|
||||||
|
* `enabled`: No longer used. If you set this to something other than true,
|
||||||
|
GNU social will no longer run.
|
||||||
|
|
||||||
|
|
||||||
|
throttle
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For notice-posting throttles.
|
||||||
|
|
||||||
|
* `enabled`: Whether to throttle posting. Defaults to false.
|
||||||
|
|
||||||
|
* `count`: Each user can make this many posts in 'timespan' seconds. So, if count
|
||||||
|
is 100 and timespan is 3600, then there can be only 100 posts
|
||||||
|
from a user every hour.
|
||||||
|
|
||||||
|
* `timespan`: see 'count'.
|
||||||
|
|
||||||
|
|
||||||
|
profile
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Profile management.
|
||||||
|
|
||||||
|
* `biolimit`: max character length of bio; 0 means no limit; null means to use
|
||||||
|
the site text limit default.
|
||||||
|
|
||||||
|
* `backup`: whether users can backup their own profiles. Defaults to false.
|
||||||
|
|
||||||
|
* `restore`: whether users can restore their profiles from backup files. Defaults
|
||||||
|
to false.
|
||||||
|
|
||||||
|
* `delete`: whether users can delete their own accounts. Defaults to false.
|
||||||
|
|
||||||
|
* `move`: whether users can move their accounts to another server. Defaults
|
||||||
|
to true.
|
||||||
|
|
||||||
|
|
||||||
|
newuser
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Options with new users.
|
||||||
|
|
||||||
|
* `default`: nickname of a user account to automatically subscribe new
|
||||||
|
users to. Typically this would be system account for e.g.
|
||||||
|
service updates or announcements. Users are able to unsub
|
||||||
|
if they want. Default is null; no auto subscribe.
|
||||||
|
|
||||||
|
* `welcome`: nickname of a user account that sends welcome messages to new
|
||||||
|
users. Can be the same as 'default' account, although on
|
||||||
|
busy servers it may be a good idea to keep that one just for
|
||||||
|
'urgent' messages. Default is null; no message.
|
||||||
|
|
||||||
|
If either of these special user accounts are specified, the users should
|
||||||
|
be created before the configuration is updated.
|
||||||
|
|
||||||
|
|
||||||
|
attachments
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The software lets users upload files with their notices. You can configure
|
||||||
|
the types of accepted files by mime types and a trio of quota options:
|
||||||
|
per file, per user (total), per user per month.
|
||||||
|
|
||||||
|
We suggest the use of the pecl file_info extension to handle mime type
|
||||||
|
detection.
|
||||||
|
|
||||||
|
* `supported`: an array of mime types you accept to store and distribute,
|
||||||
|
like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
|
||||||
|
setup your server to properly recognize the types you want to
|
||||||
|
support. It's important to use the result of calling `image_type_to_extension`
|
||||||
|
for the appropriate image type, in the case of images. This is so all parts of
|
||||||
|
the code see the same extension for each image type (jpg vs jpeg).
|
||||||
|
For example, to enable BMP uploads, add this to the config.php file:
|
||||||
|
$config['attachments']['supported'][image_type_to_mime_type(IMAGETYPE_GIF)]
|
||||||
|
= image_type_to_extension(IMAGETYPE_GIF);
|
||||||
|
See https://www.php.net/manual/en/function.image-type-to-mime-type.php for a
|
||||||
|
list of such constants. If a filetype is not listed there, it's possible to add
|
||||||
|
the mimetype and the extension by hand, but they need to match those returned by
|
||||||
|
the file command.
|
||||||
|
|
||||||
|
* `uploads`: false to disable uploading files with notices (true by default).
|
||||||
|
|
||||||
|
For quotas, be sure you've set the upload_max_filesize and post_max_size
|
||||||
|
in php.ini to be large enough to handle your upload. In httpd.conf
|
||||||
|
(if you're using apache), check that the LimitRequestBody directive isn't
|
||||||
|
set too low (it's optional, so it may not be there at all).
|
||||||
|
|
||||||
|
* `extblacklist`: associative array to either deny certain extensions or
|
||||||
|
change them to a different one. For example:
|
||||||
|
|
||||||
|
$config['attachments']['extblacklist']['php'] = 'phps'; // this turns .php into .phps
|
||||||
|
$config['attachments']['extblacklist']['exe'] = false; // this would deny any uploads
|
||||||
|
// of files with the "exe" extension
|
||||||
|
|
||||||
|
* `process_links`: follow redirects and save all available file information
|
||||||
|
(mimetype, date, size, oembed, etc.). Defaults to true.
|
||||||
|
|
||||||
|
* `file_quota`: maximum size for a single file upload in bytes. A user can send
|
||||||
|
any amount of notices with attachments as long as each attachment
|
||||||
|
is smaller than file_quota.
|
||||||
|
|
||||||
|
* `user_quota`: total size in bytes a user can store on this server. Each user
|
||||||
|
can store any number of files as long as their total size does
|
||||||
|
not exceed the user_quota.
|
||||||
|
|
||||||
|
* `monthly_quota`: total size permitted in the current month. This is the total
|
||||||
|
size in bytes that a user can upload each month.
|
||||||
|
|
||||||
|
* `dir`: directory accessible to the Web process where uploads should go.
|
||||||
|
Defaults to the 'file' subdirectory of the install directory, which
|
||||||
|
should be writeable by the Web user.
|
||||||
|
|
||||||
|
* `server`: server name to use when creating URLs for uploaded files.
|
||||||
|
Defaults to null, meaning to use the default Web server. Using
|
||||||
|
a virtual server here can speed up Web performance.
|
||||||
|
|
||||||
|
* `path`: URL path, relative to the server, to find files. Defaults to
|
||||||
|
main path + '/file/'.
|
||||||
|
|
||||||
|
* `ssl`: whether to use HTTPS for file URLs. Defaults to null, meaning to
|
||||||
|
guess based on other SSL settings.
|
||||||
|
|
||||||
|
* `sslserver`: if specified, this server will be used when creating HTTPS
|
||||||
|
URLs. Otherwise, the site SSL server will be used, with /file/ path.
|
||||||
|
|
||||||
|
* `sslpath`: if this and the sslserver are specified, this path will be used
|
||||||
|
when creating HTTPS URLs. Otherwise, the attachments|path value
|
||||||
|
will be used.
|
||||||
|
|
||||||
|
* `show_thumbs`: show thumbnails in notice lists for uploaded images, and photos
|
||||||
|
and videos linked remotely that provide oEmbed info. Defaults to true.
|
||||||
|
|
||||||
|
* `show_html`: show (filtered) text/html attachments (and oEmbed HTML etc.).
|
||||||
|
Doesn't affect AJAX calls. Defaults to false.
|
||||||
|
|
||||||
|
* `filename_base`: for new files, choose one: 'upload', 'hash'. Defaults to hash.
|
||||||
|
|
||||||
|
|
||||||
|
group
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Options for group functionality.
|
||||||
|
|
||||||
|
* `maxaliases`: maximum number of aliases a group can have. Default 3. Set
|
||||||
|
to 0 or less to prevent aliases in a group.
|
||||||
|
|
||||||
|
* `desclimit`: maximum number of characters to allow in group descriptions.
|
||||||
|
null (default) means to use the site-wide text limits. 0
|
||||||
|
means no limit.
|
||||||
|
|
||||||
|
* `addtag`: Whether to add a tag for the group nickname for every group post
|
||||||
|
(pre-1.0.x behaviour). Defaults to false.
|
||||||
|
|
||||||
|
|
||||||
|
search
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Some stuff for search.
|
||||||
|
|
||||||
|
* `type`: type of search. Ignored if PostgreSQL or Sphinx are enabled. Can either
|
||||||
|
be 'fulltext' or 'like' (default). The former is faster and more efficient
|
||||||
|
but requires the lame old MyISAM engine for MySQL. The latter
|
||||||
|
will work with InnoDB but could be miserably slow on large
|
||||||
|
systems. We'll probably add another type sometime in the future,
|
||||||
|
with our own indexing system (maybe like MediaWiki's).
|
||||||
|
|
||||||
|
|
||||||
|
sessions
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Session handling.
|
||||||
|
|
||||||
|
* `handle`: boolean. Whether we should register our own PHP session-handling
|
||||||
|
code (using the database and cache layers if enabled). Defaults to false.
|
||||||
|
Setting this to true makes some sense on large or multi-server
|
||||||
|
sites, but it probably won't hurt for smaller ones, either.
|
||||||
|
|
||||||
|
* `debug`: whether to output debugging info for session storage. Can help
|
||||||
|
with weird session bugs, sometimes. Default false.
|
||||||
|
|
||||||
|
|
||||||
|
ping
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Using the "XML-RPC Ping" method initiated by weblogs.com, the site can
|
||||||
|
notify third-party servers of updates.
|
||||||
|
|
||||||
|
* `notify`: an array of URLs for ping endpoints. Default is the empty
|
||||||
|
array (no notification).
|
||||||
|
|
||||||
|
|
||||||
|
notice
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Configuration options specific to notices.
|
||||||
|
|
||||||
|
* `contentlimit`: max length of the plain-text content of a notice.
|
||||||
|
Default is null, meaning to use the site-wide text limit.
|
||||||
|
0 means no limit.
|
||||||
|
|
||||||
|
* `defaultscope`: default scope for notices. If null, the default
|
||||||
|
scope depends on site/private. It's 1 if the site is private,
|
||||||
|
0 otherwise. Set this value to override.
|
||||||
|
|
||||||
|
|
||||||
|
message
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Configuration options specific to messages.
|
||||||
|
|
||||||
|
* `contentlimit`: max length of the plain-text content of a message.
|
||||||
|
Default is null, meaning to use the site-wide text limit.
|
||||||
|
0 means no limit.
|
||||||
|
|
||||||
|
|
||||||
|
logincommand
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Configuration options for the login command.
|
||||||
|
|
||||||
|
* `disabled`: whether to enable this command. If enabled, users who send
|
||||||
|
the text 'login' to the site through any channel will
|
||||||
|
receive a link to login to the site automatically in return.
|
||||||
|
Possibly useful for users who primarily use an XMPP or SMS
|
||||||
|
interface and can't be bothered to remember their site
|
||||||
|
password. Note that the security implications of this are
|
||||||
|
pretty serious and have not been thoroughly tested. You
|
||||||
|
should enable it only after you've convinced yourself that
|
||||||
|
it is safe. Default is 'false'.
|
||||||
|
|
||||||
|
|
||||||
|
singleuser
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
If an installation has only one user, this can simplify a lot of the
|
||||||
|
interface. It also makes the user's profile the root URL.
|
||||||
|
|
||||||
|
* `enabled` (boolean, default true): Whether to run in "single user mode".
|
||||||
|
|
||||||
|
* `nickname` (string, default null): nickname of the single user. If no nickname is
|
||||||
|
specified, the site owner account will be used (if present).
|
||||||
|
|
||||||
|
|
||||||
|
robotstxt
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
We put out a default robots.txt file to guide the processing of
|
||||||
|
Web crawlers. See http://www.robotstxt.org/ for more information
|
||||||
|
on the format of this file.
|
||||||
|
|
||||||
|
* `crawldelay`: if non-empty, this value is provided as the Crawl-Delay:
|
||||||
|
for the robots.txt file. see <https://en.wikipedia.org/wiki/Robots_exclusion_standard#Crawl-delay_directive>
|
||||||
|
for more information. Default is zero, no explicit delay.
|
||||||
|
|
||||||
|
* `disallow`: Array of (virtual) directories to disallow. Default is 'main',
|
||||||
|
'search', 'message', 'settings', 'admin'. Ignored when site
|
||||||
|
is private, in which case the entire site ('/') is disallowed.
|
||||||
|
|
||||||
|
|
||||||
|
api
|
||||||
|
---
|
||||||
|
|
||||||
|
Options for the Twitter-like API.
|
||||||
|
|
||||||
|
* `realm`: HTTP Basic Auth realm (see http://tools.ietf.org/html/rfc2617
|
||||||
|
for details). Some third-party tools like ping.fm want this to be
|
||||||
|
'Identi.ca API', so set it to that if you want to. default = null,
|
||||||
|
meaning 'something based on the site name'.
|
||||||
|
|
||||||
|
|
||||||
|
nofollow
|
||||||
|
--------
|
||||||
|
|
||||||
|
We optionally put 'rel="nofollow"' on some links in some pages. The
|
||||||
|
following configuration settings let you fine-tune how or when things
|
||||||
|
are nofollowed. See http://en.wikipedia.org/wiki/Nofollow for more
|
||||||
|
information on what 'nofollow' means.
|
||||||
|
|
||||||
|
* `subscribers`: whether to nofollow links to subscribers on the profile
|
||||||
|
and personal pages. Default is true.
|
||||||
|
|
||||||
|
* `members`: links to members on the group page. Default true.
|
||||||
|
|
||||||
|
* `peopletag`: links to people listed in the peopletag page. Default true.
|
||||||
|
|
||||||
|
* `external`: external links in notices. One of three values: 'sometimes',
|
||||||
|
'always', 'never'. If 'sometimes', then external links are not
|
||||||
|
nofollowed on profile, notice, and favorites page. Default is
|
||||||
|
'sometimes'.
|
||||||
|
|
||||||
|
url
|
||||||
|
---
|
||||||
|
|
||||||
|
These are some options for fine-tuning how and when the server will
|
||||||
|
shorten URLs.
|
||||||
|
|
||||||
|
* `shortener`: URL shortening service to use by default. Users can override
|
||||||
|
individually. 'internal' by default.
|
||||||
|
|
||||||
|
* `maxurllength`: If an URL is strictly longer than this limit, it will be
|
||||||
|
shortened. Note that the URL shortener service may return an
|
||||||
|
URL longer than this limit. Defaults to 100. Users can
|
||||||
|
override. If set to 0, all URLs will be shortened.
|
||||||
|
|
||||||
|
* `maxnoticelength`: If a notice is strictly longer than this limit, all
|
||||||
|
URLs in the notice will be shortened. Users can override.
|
||||||
|
-1 means the text limit for notices.
|
||||||
|
|
||||||
|
|
||||||
|
router
|
||||||
|
------
|
||||||
|
|
||||||
|
We use a router class for mapping URLs to code. This section controls
|
||||||
|
how that router works.
|
||||||
|
|
||||||
|
* `cache`: whether to cache the router in cache layers. Defaults to true,
|
||||||
|
but may be set to false for developers (who might be actively
|
||||||
|
adding pages, so won't want the router cached) or others who see
|
||||||
|
strange behavior. You're unlikely to need this unless developing..
|
||||||
|
|
||||||
|
|
||||||
|
http
|
||||||
|
----
|
||||||
|
|
||||||
|
Settings for the HTTP client.
|
||||||
|
|
||||||
|
* `ssl_cafile`: location of the CA file for SSL. If not set, won't verify
|
||||||
|
SSL peers. Default unset.
|
||||||
|
|
||||||
|
* `curl`: Use cURL <http://curl.haxx.se/> for doing HTTP calls. You must
|
||||||
|
have the PHP curl extension installed for this to work.
|
||||||
|
|
||||||
|
* `proxy_host`: Host to use for proxying HTTP requests. If unset, doesn't
|
||||||
|
do any HTTP proxy stuff. Default unset.
|
||||||
|
|
||||||
|
* `proxy_port`: Port to use to connect to HTTP proxy host. Default null.
|
||||||
|
|
||||||
|
* `proxy_user`: Username to use for authenticating to the HTTP proxy. Default null.
|
||||||
|
|
||||||
|
* `proxy_password`: Password to use for authenticating to the HTTP proxy. Default null.
|
||||||
|
|
||||||
|
* `proxy_auth_scheme`: Scheme to use for authenticating to the HTTP proxy. Default null.
|
||||||
|
|
||||||
|
|
||||||
|
plugins
|
||||||
|
-------
|
||||||
|
|
||||||
|
* `default`: associative array mapping plugin name to array of arguments. To disable
|
||||||
|
a default plugin, unset its value in this array.
|
||||||
|
|
||||||
|
* `locale_path`: path for finding plugin locale files. In the plugin's directory
|
||||||
|
by default.
|
||||||
|
|
||||||
|
* `server`: Server to find static files for a plugin when the page is plain old HTTP.
|
||||||
|
Defaults to site/server (same as pages). Use this to move plugin CSS and
|
||||||
|
JS files to a CDN.
|
||||||
|
|
||||||
|
* `sslserver`: Server to find static files for a plugin when the page is HTTPS. Defaults
|
||||||
|
to site/server (same as pages). Use this to move plugin CSS and JS files
|
||||||
|
to a CDN.
|
||||||
|
|
||||||
|
* `path`: Path to the plugin files. defaults to site/path + '/plugins/'. Expects that
|
||||||
|
each plugin will have a subdirectory at plugins/NameOfPlugin. Change this
|
||||||
|
if you're using a CDN.
|
||||||
|
|
||||||
|
* `sslpath`: Path to use on the SSL server. Same as plugins/path.
|
||||||
|
|
||||||
|
|
||||||
|
performance
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* `high`: if you need high performance, or if you're seeing bad
|
||||||
|
performance, set this to true. It will turn off some high-intensity code from
|
||||||
|
the site.
|
||||||
|
|
||||||
|
|
||||||
|
oldschool
|
||||||
|
---------
|
||||||
|
|
||||||
|
* `enabled`: enable certain old-style user settings options, like stream-only mode,
|
||||||
|
conversation trees, and nicknames in streams. Off by default, and
|
||||||
|
may not be well supported in future versions.
|
@@ -10,13 +10,13 @@ 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
|
In the simplest case, you can add a function to config.php and use the
|
||||||
Event::addHandler() function to hook an event:
|
Event::addHandler() function to hook an event:
|
||||||
|
|
||||||
function AddGoogleLink($action)
|
function AddMyWebsiteLink($action)
|
||||||
{
|
{
|
||||||
$action->menuItem('http://www.google.com/', _('Google'), _('Search engine'));
|
$action->menuItem('http://mywebsite.net/', _('My web site'), _('Example web link'));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::addHandler('EndPrimaryNav', 'AddGoogleLink');
|
Event::addHandler('EndPrimaryNav', 'AddMyWebsiteLink');
|
||||||
|
|
||||||
This adds a menu item to the end of the main navigation menu. You can
|
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
|
see the list of existing events, and parameters that handlers must
|
@@ -0,0 +1,15 @@
|
|||||||
|
#Simple way to Webfinger enable your domain -- needs PHP
|
||||||
|
|
||||||
|
##Step 1
|
||||||
|
|
||||||
|
Put the 'dot-well-known' on your website, so it loads at:
|
||||||
|
|
||||||
|
https://another_cool.org/.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/webfinger/index.php file and replace "https://www.example.org/gnusocial/index.php" with the domain name
|
||||||
|
you're hosting the .well-known handler on.
|
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// FIXME: REPLACE \/ here
|
||||||
|
define('MY_GNUSOCIAL', 'https://www.example.org/gnusocial/index.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a general solution for when you can't have your GNU social instance in the domain root and for when you want to
|
||||||
|
* socialfy from another domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// From https://www.php.net/manual/en/function.getallheaders.php#84262 (joyview at gmail dot com)
|
||||||
|
if (!function_exists('getallheaders')) {
|
||||||
|
function getallheaders()
|
||||||
|
{
|
||||||
|
$headers = [];
|
||||||
|
foreach ($_SERVER as $name => $value) {
|
||||||
|
if (substr($name, 0, 5) == 'HTTP_') {
|
||||||
|
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, getallheaders());
|
||||||
|
curl_setopt($ch, CURLOPT_URL, MY_GNUSOCIAL . str_replace('webfinger/', 'webfinger', $_SERVER['REQUEST_URI']));
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||||
|
$body = substr($response, $header_size);
|
||||||
|
// From https://stackoverflow.com/a/10590242 (c.hill)
|
||||||
|
function get_headers_from_curl_response($response)
|
||||||
|
{
|
||||||
|
$headers = array();
|
||||||
|
|
||||||
|
$header_text = substr($response, 0, strpos($response, "\r\n\r\n"));
|
||||||
|
|
||||||
|
foreach (explode("\r\n", $header_text) as $i => $line) {
|
||||||
|
if ($i === 0) {
|
||||||
|
$headers['http_code'] = $line;
|
||||||
|
} else {
|
||||||
|
list($key, $value) = explode(': ', $line);
|
||||||
|
|
||||||
|
$headers[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
$headers = get_headers_from_curl_response($response);
|
||||||
|
foreach ($headers as $name => $value) {
|
||||||
|
header("{$name}: $value");
|
||||||
|
}
|
||||||
|
echo $body;
|
||||||
|
curl_close($ch);
|
@@ -11,6 +11,9 @@ and follow this procedure:
|
|||||||
0. Backup your data. The StatusNet upgrade discussions below have some
|
0. Backup your data. The StatusNet upgrade discussions below have some
|
||||||
guidelines to back up the database and files (mysqldump and rsync).
|
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
|
1. Stop your queue daemons (you can run this command even if you do not
|
||||||
use the queue daemons):
|
use the queue daemons):
|
||||||
$ bash scripts/stopdaemons.sh
|
$ bash scripts/stopdaemons.sh
|
@@ -44,6 +44,11 @@
|
|||||||
# RewriteRule (.*) index.php/$1 [L,QSA]
|
# RewriteRule (.*) index.php/$1 [L,QSA]
|
||||||
</IfModule>
|
</IfModule>
|
||||||
|
|
||||||
|
# Enable X-Sendfile if available. Still needs to be enabled in the config
|
||||||
|
<IfModule mod_xsendfile.c>
|
||||||
|
XSendFile On
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
<FilesMatch "\.(ini)">
|
<FilesMatch "\.(ini)">
|
||||||
<IfVersion < 2.3>
|
<IfVersion < 2.3>
|
||||||
Order allow,deny
|
Order allow,deny
|
@@ -0,0 +1,97 @@
|
|||||||
|
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 (GNU social's root + /public)
|
||||||
|
root /var/www/gnusocial/public;
|
||||||
|
|
||||||
|
# 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;
|
||||||
|
|
||||||
|
# X-Accel/X-Sendfile. Still needs to be enabled in the config
|
||||||
|
location /file {
|
||||||
|
internal;
|
||||||
|
# FIXME: Change "/path/to/gnusocial/root/" to the folder where
|
||||||
|
# attachments are stored (normally the same as the site root)
|
||||||
|
root /path/to/gnusocial/root/;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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;
|
||||||
|
# }
|
||||||
|
}
|
17
DOCUMENTATION/VERSIONING.md
Normal file
17
DOCUMENTATION/VERSIONING.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Versioning
|
||||||
|
|
||||||
|
## Release cycle
|
||||||
|
We follow Semantic Versioning as defined on [https://semver.org/](https://semver.org).
|
||||||
|
|
||||||
|
The GNU social platform has a monthly release cycle. That is, we only increment the version number on day 1 of each month.
|
||||||
|
|
||||||
|
For GNU social plugins, we increment version number by commit. Plugins update have a propagation of the same type in the
|
||||||
|
GNU social's monthly version bump.
|
||||||
|
|
||||||
|
If we have various patch type updates in a month, we only bump it by one in the end of the month. If in the same month
|
||||||
|
we have a minor too, we will only bump the minor value.
|
||||||
|
|
||||||
|
# Lifecycle
|
||||||
|
|
||||||
|
GNU social has 'dev', 'alpha', 'beta', 'rc' and 'release' cycles. We usually are in `dev` during summer. When we finish a `dev` cycle we release an `alpha` (`dev`s aren't tagged as releases). From `alpha` to `release` it depends on how perfect GNU social is after the end of the `dev` cycle. But we use the number after `alpha` instead of `patch` number for small bug fixes when in this cycle. When we finally go from a `r`elease `c`andidate to a `release`, we party... and we use semver for all the small changes until we start working in another `dev` cycle (usually on another summer).
|
||||||
|
|
@@ -16,6 +16,7 @@ TABLE OF CONTENTS
|
|||||||
* After installation
|
* After installation
|
||||||
- Backups
|
- Backups
|
||||||
- Upgrading
|
- Upgrading
|
||||||
|
* Additional configuration
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
=============
|
=============
|
||||||
@@ -26,32 +27,32 @@ PHP modules
|
|||||||
The following software packages are *required* for this software to
|
The following software packages are *required* for this software to
|
||||||
run correctly.
|
run correctly.
|
||||||
|
|
||||||
- PHP 5.5+ For newer versions, some functions that are used may be
|
- PHP 7+ PHP7.x is also supported.
|
||||||
disabled by default, such as the pcntl_* family. See the
|
- MariaDB 5+ MariaDB 10.x is also supported.
|
||||||
section on 'Queues and daemons' for more information.
|
|
||||||
- MariaDB 5+ GNU Social uses, by default, a MariaDB server for data
|
|
||||||
storage. Versions 5.x and 10.x have both reportedly
|
|
||||||
worked well. It is also possible to run MySQL 5.5+.
|
|
||||||
- Web server Apache, lighttpd and nginx will all work. CGI mode is
|
- Web server Apache, lighttpd and nginx will all work. CGI mode is
|
||||||
recommended and also some variant of 'suexec' (or a
|
recommended and also some variant of 'suexec' (or a
|
||||||
proper setup php-fpm pool)
|
proper setup php-fpm pool)
|
||||||
NOTE: mod_rewrite or its equivalent is extremely useful.
|
NOTE: mod_rewrite or its equivalent is extremely useful.
|
||||||
|
|
||||||
Your PHP installation must include the following PHP extensions for a
|
Your PHP installation must include the following PHP extensions for a
|
||||||
functional setup of GNU Social:
|
functional setup of GNU social:
|
||||||
|
|
||||||
- openssl (compiled in for Debian, enabled manually in Arch Linux)
|
- openssl (compiled in for Debian, enabled manually in Arch Linux)
|
||||||
- php5-curl Fetching files by HTTP.
|
- php-curl Fetching files by HTTP.
|
||||||
- php5-gd Image manipulation (scaling).
|
- php-exif Exchangeable image information.
|
||||||
- php5-gmp For Salmon signatures (part of OStatus).
|
- php-gd Image manipulation (scaling).
|
||||||
- php5-intl Internationalization support (transliteration et al).
|
- php-intl Internationalization support (transliteration et al).
|
||||||
- php5-json For WebFinger lookups and more.
|
- php-json For WebFinger lookups and more.
|
||||||
- php5-mysqlnd The native driver for PHP5 MariaDB connections. If you
|
- php-mbstring String manipulation
|
||||||
use MySQL, 'php5-mysql' or 'php5-mysqli' may be enough.
|
- 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
|
||||||
|
|
||||||
The above package names are for Debian based systems. In the case of
|
NOTE: Some distros require manual enabling in the relevant php.ini for some modules.
|
||||||
Arch Linux, PHP is compiled with support for most extensions but they
|
|
||||||
require manual enabling in the relevant php.ini file (mostly php5-gmp).
|
|
||||||
|
|
||||||
Better performance
|
Better performance
|
||||||
------------------
|
------------------
|
||||||
@@ -69,6 +70,7 @@ For some functionality, you will also need the following extensions:
|
|||||||
- gettext For multiple languages. Default on many PHP installs;
|
- gettext For multiple languages. Default on many PHP installs;
|
||||||
will be emulated if not present.
|
will be emulated if not present.
|
||||||
- exif For thumbnails to be properly oriented.
|
- 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
|
You may also experience better performance from your site if you configure
|
||||||
a PHP cache/accelerator. Most distributions come with "opcache" support.
|
a PHP cache/accelerator. Most distributions come with "opcache" support.
|
||||||
@@ -100,7 +102,7 @@ especially if you've previously installed PHP/MariaDB packages.
|
|||||||
|
|
||||||
This will often make your GNU Social instance available in the gnusocial
|
This will often make your GNU Social instance available in the gnusocial
|
||||||
path of your server, like "http://example.net/gnusocial". "social" or
|
path of your server, like "http://example.net/gnusocial". "social" or
|
||||||
"blog" might also be good path names. If you know how to configure
|
"blog" might also be good path names. If you know how to configure
|
||||||
virtual hosts on your web server, you can try setting up
|
virtual hosts on your web server, you can try setting up
|
||||||
"http://social.example.net/" or the like.
|
"http://social.example.net/" or the like.
|
||||||
|
|
||||||
@@ -124,17 +126,7 @@ especially if you've previously installed PHP/MariaDB packages.
|
|||||||
that user's default group instead. As a last resort, you can create
|
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.
|
a new group like "gnusocial" and add the Web server's user to the group.
|
||||||
|
|
||||||
4. You should also take this moment to make your 'avatar' and 'file' sub-
|
4. Create a database to hold your site data. Something like this
|
||||||
directories writeable by the Web server. The _insecure_ way to do
|
|
||||||
this is:
|
|
||||||
|
|
||||||
chmod a+w /var/www/gnusocial/avatar
|
|
||||||
chmod a+w /var/www/gnusocial/file
|
|
||||||
|
|
||||||
You can also make the avatar, and file directories just writable by
|
|
||||||
the Web server group, as noted above.
|
|
||||||
|
|
||||||
5. Create a database to hold your site data. Something like this
|
|
||||||
should work (you will be prompted for your database password):
|
should work (you will be prompted for your database password):
|
||||||
|
|
||||||
mysqladmin -u "root" -p create social
|
mysqladmin -u "root" -p create social
|
||||||
@@ -147,7 +139,7 @@ especially if you've previously installed PHP/MariaDB packages.
|
|||||||
a tool like phpMyAdmin to create a database. Check your hosting
|
a tool like phpMyAdmin to create a database. Check your hosting
|
||||||
service's documentation for how to create a new MariaDB database.)
|
service's documentation for how to create a new MariaDB database.)
|
||||||
|
|
||||||
6. Create a new database account that GNU Social will use to access the
|
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
|
database. If you have shell access, this will probably work from the
|
||||||
MariaDB shell:
|
MariaDB shell:
|
||||||
|
|
||||||
@@ -159,7 +151,7 @@ especially if you've previously installed PHP/MariaDB packages.
|
|||||||
to your preferred new database username and password. You may want to
|
to your preferred new database username and password. You may want to
|
||||||
test logging in to MariaDB as this new user.
|
test logging in to MariaDB as this new user.
|
||||||
|
|
||||||
7. In a browser, navigate to the GNU Social install script; something like:
|
6. In a browser, navigate to the GNU Social install script; something like:
|
||||||
|
|
||||||
https://social.example.net/install.php
|
https://social.example.net/install.php
|
||||||
|
|
||||||
@@ -167,7 +159,7 @@ especially if you've previously installed PHP/MariaDB packages.
|
|||||||
install program will configure your site and install the initial,
|
install program will configure your site and install the initial,
|
||||||
almost-empty database.
|
almost-empty database.
|
||||||
|
|
||||||
8. You should now be able to navigate to your social site's main directory
|
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
|
and see the "Public Timeline", which will probably be empty. You can
|
||||||
now register new user, post some notices, edit your profile, etc.
|
now register new user, post some notices, edit your profile, etc.
|
||||||
|
|
||||||
@@ -194,7 +186,7 @@ your server (like lighttpd or nginx).
|
|||||||
1. See the instructions for each respective webserver software:
|
1. See the instructions for each respective webserver software:
|
||||||
* For Apache, inspect the "htaccess.sample" file and save it as
|
* For Apache, inspect the "htaccess.sample" file and save it as
|
||||||
".htaccess" after making any necessary modifications. Our sample
|
".htaccess" after making any necessary modifications. Our sample
|
||||||
file is well commented.
|
file is well commented.
|
||||||
* For lighttpd, inspect the lighttpd.conf.example file and apply the
|
* For lighttpd, inspect the lighttpd.conf.example file and apply the
|
||||||
appropriate changes in your virtualhost configuration for lighttpd.
|
appropriate changes in your virtualhost configuration for lighttpd.
|
||||||
* For nginx, inspect the nginx.conf.sample file and apply the appropriate
|
* For nginx, inspect the nginx.conf.sample file and apply the appropriate
|
||||||
@@ -204,7 +196,7 @@ your server (like lighttpd or nginx).
|
|||||||
|
|
||||||
2. Assuming your webserver is properly configured and have its settings
|
2. Assuming your webserver is properly configured and have its settings
|
||||||
applied (remember to reload/restart it), you can add this to your
|
applied (remember to reload/restart it), you can add this to your
|
||||||
GNU social's config.php file:
|
GNU social's config.php file:
|
||||||
$config['site']['fancy'] = true;
|
$config['site']['fancy'] = true;
|
||||||
|
|
||||||
You should now be able to navigate to a "fancy" URL on your server,
|
You should now be able to navigate to a "fancy" URL on your server,
|
||||||
@@ -229,10 +221,10 @@ following files:
|
|||||||
display.css: a CSS2 file for "default" styling for all browsers.
|
display.css: a CSS2 file for "default" styling for all browsers.
|
||||||
logo.png: a logo image for the site.
|
logo.png: a logo image for the site.
|
||||||
default-avatar-profile.png: a 96x96 pixel image to use as the avatar for
|
default-avatar-profile.png: a 96x96 pixel image to use as the avatar for
|
||||||
users who don't upload their own.
|
users who don't upload their own.
|
||||||
default-avatar-stream.png: Ditto, but 48x48. For streams of notices.
|
default-avatar-stream.png: Ditto, but 48x48. For streams of notices.
|
||||||
default-avatar-mini.png: Ditto ditto, but 24x24. For subscriptions
|
default-avatar-mini.png: Ditto ditto, but 24x24. For subscriptions
|
||||||
listing on profile pages.
|
listing on profile pages.
|
||||||
|
|
||||||
You may want to start by copying the files from the default theme to
|
You may want to start by copying the files from the default theme to
|
||||||
your own directory.
|
your own directory.
|
||||||
@@ -244,7 +236,7 @@ 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
|
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
|
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,
|
guarantee that there are no leaks (what a public network sees as features,
|
||||||
private sites will likely see as bugs).
|
private sites will likely see as bugs).
|
||||||
|
|
||||||
Private nodes are however an easy way to easily setup collaboration and
|
Private nodes are however an easy way to easily setup collaboration and
|
||||||
image sharing within a workgroup or a smaller community where federation
|
image sharing within a workgroup or a smaller community where federation
|
||||||
@@ -464,3 +456,8 @@ Upgrading
|
|||||||
Upgrading is strongly recommended to stay up to date with security fixes
|
Upgrading is strongly recommended to stay up to date with security fixes
|
||||||
and new features. For instructions on how to upgrade GNU social code,
|
and new features. For instructions on how to upgrade GNU social code,
|
||||||
please see the UPGRADE file.
|
please see the UPGRADE file.
|
||||||
|
|
||||||
|
Additional configuration
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Please refer to DOCUMENTATION/SYSTEM_ADMINISTRATORS/CONFIGURE for information.
|
3
Makefile
3
Makefile
@@ -7,6 +7,9 @@ plugin_mo = $(patsubst %.po,%.mo,$(wildcard plugins/*/locale/*/LC_MESSAGES/*.po)
|
|||||||
|
|
||||||
translations : $(core_mo) $(plugin_mo)
|
translations : $(core_mo) $(plugin_mo)
|
||||||
|
|
||||||
|
upgrade :
|
||||||
|
php scripts/upgrade.php
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
rm -f $(core_mo) $(plugin_mo)
|
rm -f $(core_mo) $(plugin_mo)
|
||||||
|
|
||||||
|
166
README.md
166
README.md
@@ -1,27 +1,22 @@
|
|||||||
# GNU social 1.2.x
|
# GNU social 2.0.x
|
||||||
2015
|
(c) 2010-2019 Free Software Foundation, Inc
|
||||||
|
|
||||||
(c) Free Software Foundation, Inc
|
|
||||||
(c) StatusNet, Inc
|
|
||||||
|
|
||||||
This is the README file for GNU social, the free
|
This is the README file for GNU social, the free
|
||||||
software social networking platform. It includes
|
software social networking platform. It includes
|
||||||
general information about the software and the
|
general information about the software and the
|
||||||
project.
|
project.
|
||||||
|
|
||||||
Some other files to review:
|
The file INSTALL.md has useful instructions on how to
|
||||||
|
install this software.
|
||||||
|
|
||||||
- INSTALL: instructions on how to install the software.
|
System administrators may find the `DOCUMENTATION/SYSTEM_ADMINISTRATORS`
|
||||||
- UPGRADE: upgrading from earlier versions
|
directory useful, namely:
|
||||||
- CONFIGURE: configuration options in gruesome detail.
|
|
||||||
- PLUGINS.txt: how to install and configure plugins.
|
|
||||||
- EVENTS.txt: events supported by the plugin system
|
|
||||||
- COPYING: full text of the software license
|
|
||||||
|
|
||||||
Information on using GNU social can be found in
|
- upgrade_from: upgrading from different software
|
||||||
the "doc" subdirectory or in the "help" section
|
- CONFIGURE.md: configuration options in gruesome detail.
|
||||||
on-line, or you can catch us on IRC in #social on
|
- PLUGINS.md: how to install and configure plugins.
|
||||||
the freenode network.
|
|
||||||
|
Developers may find the `DOCUMENTATION/DEVELOPERS` directory useful.
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
@@ -32,16 +27,16 @@ polls, announce events, or other social activities
|
|||||||
(and you can add more!). Users can choose which
|
(and you can add more!). Users can choose which
|
||||||
people to "follow" and receive only their friends'
|
people to "follow" and receive only their friends'
|
||||||
or colleagues' status messages. It provides a
|
or colleagues' status messages. It provides a
|
||||||
similar service to sites like Twitter, Google+ or
|
similar service to proprietary social network sites,
|
||||||
Facebook, but is much more awesome.
|
but is much more awesome.
|
||||||
|
|
||||||
With a little work, status messages can be sent to
|
With a little work, status messages can be sent to
|
||||||
mobile phones, instant messenger programs (using
|
mobile phones, instant messenger programs (using
|
||||||
XMPP), and specially-designed desktop clients that
|
XMPP), and specially-designed desktop clients that
|
||||||
support the Twitter API.
|
support the Twitter API.
|
||||||
|
|
||||||
GNU social supports an open standard called
|
GNU social supports open standards (such as OStatus
|
||||||
OStatus <https://www.w3.org/community/ostatus/> that lets users in
|
<https://www.w3.org/community/ostatus/>) that lets users in
|
||||||
different networks follow each other. It enables a
|
different networks follow each other. It enables a
|
||||||
distributed social network spread all across the
|
distributed social network spread all across the
|
||||||
Web.
|
Web.
|
||||||
@@ -98,31 +93,7 @@ liberal terms, but those terms may differ in detail from the AGPL's
|
|||||||
particulars. See each package's license file in the extlib directory
|
particulars. See each package's license file in the extlib directory
|
||||||
for additional terms.
|
for additional terms.
|
||||||
|
|
||||||
## New this version
|
Refer to COPYING.md for full text of the software license..
|
||||||
|
|
||||||
This is the development branch for the 1.2.x version of GNU social.
|
|
||||||
All daring 1.1.x admins should upgrade to this version.
|
|
||||||
|
|
||||||
So far it includes the following changes:
|
|
||||||
|
|
||||||
- Backing up a user's account is more and more complete.
|
|
||||||
- Emojis 😸 (utf8mb4 support)
|
|
||||||
|
|
||||||
The last release, 1.1.3, gave us these improvements:
|
|
||||||
|
|
||||||
- XSS security fix (thanks Simon Waters, <https://www.surevine.com/>)
|
|
||||||
- Many improvements to ease adoption of the Qvitter front-end <https://github.com/hannesmannerheim/qvitter>
|
|
||||||
- Protocol adaptions for improved performance and stability
|
|
||||||
|
|
||||||
Upgrades from _StatusNet_ 1.1.1 will also experience these improvements:
|
|
||||||
|
|
||||||
- Fixes for SQL injection errors in profile lists.
|
|
||||||
- Improved ActivityStreams JSON representation of activities and objects.
|
|
||||||
- Upgrade to the Twitter 1.1 API.
|
|
||||||
- More robust handling of errors in distribution.
|
|
||||||
- Fix error in OStatus subscription for remote groups.
|
|
||||||
- Fix error in XMPP distribution.
|
|
||||||
- Tracking of conversation URI metadata (more coherent convos)
|
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
|
|
||||||
@@ -144,17 +115,19 @@ to install the development version of GNU social.
|
|||||||
To get it, use the git version control tool
|
To get it, use the git version control tool
|
||||||
<http://git-scm.com/> like so:
|
<http://git-scm.com/> like so:
|
||||||
|
|
||||||
git clone git@git.gnu.io:gnu/gnu-social.git
|
git clone git@notabug.org:diogo/gnu-social.git
|
||||||
|
|
||||||
In the current phase of development it is probably
|
In the current phase of development it is probably
|
||||||
recommended to use git as a means to stay up to date
|
recommended to use git as a means to stay up to date
|
||||||
with the source code. You can choose between these
|
with the source code. You can choose between these
|
||||||
branches:
|
branches:
|
||||||
- 1.2.x "stable", few updates, well tested code
|
* 1.20.x "oldstable", few updates, well tested coded
|
||||||
- master "testing", more updates, usually working well
|
* master "stable", usually working well
|
||||||
- nightly "unstable", most updates, not always working
|
* nightly "testing", most updates, not always working as expected
|
||||||
|
|
||||||
To keep it up-to-date, use 'git pull'. Watch for conflicts!
|
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
|
## Further information
|
||||||
|
|
||||||
@@ -163,89 +136,22 @@ There are several ways to get more information about GNU social.
|
|||||||
* The #social IRC channel on freenode.net <https://www.freenode.net/>.
|
* 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 unofficial XMPP room linked to IRC on <xmpp:gnusocial@conference.bka.li>
|
||||||
* The GNU social website <https://gnu.io/social/>
|
* The GNU social website <https://gnu.io/social/>
|
||||||
* Following us on GNU social -- <https://quitter.se/gnusocial>
|
|
||||||
|
|
||||||
* GNU social has a bug tracker for any defects you may find, or ideas for
|
* GNU social has a bug tracker for any defects you may find, or ideas for
|
||||||
making things better. <https://git.gnu.io/gnu/gnu-social/issues/>
|
making things better. <https://notabug.org/diogo/gnu-social/issues>
|
||||||
* Patches are welcome, preferrably to our repository on git.gnu.io. <https://git.gnu.io/gnu/gnu-social>
|
* Patches are welcome, preferrably to our repository on notabug.org. <https://notabug.org/diogo/gnu-social>
|
||||||
|
|
||||||
Credits
|
## Credits
|
||||||
=======
|
|
||||||
|
|
||||||
The following is an incomplete list of developers
|
An incomplete list of developers who've worked on GNU social,
|
||||||
who've worked on GNU social, or its predecessors
|
or its predecessors StatusNet and Free Social has been made available
|
||||||
StatusNet and Free Social. Apologies for any
|
in `CREDITS.md`.
|
||||||
oversight; please let mattl@gnu.org know if
|
|
||||||
anyone's been overlooked in error.
|
|
||||||
|
|
||||||
## Project Founders
|
### Current team
|
||||||
|
|
||||||
* Matt Lee (GNU social)
|
|
||||||
* Evan Prodromou (StatusNet)
|
|
||||||
* Mikael Nordfeldth (Free Social)
|
|
||||||
|
|
||||||
Thanks to all of the StatusNet developers:
|
|
||||||
|
|
||||||
* Zach Copley, StatusNet, Inc.
|
|
||||||
* Earle Martin, StatusNet, Inc.
|
|
||||||
* Marie-Claude Doyon, designer, StatusNet, Inc.
|
|
||||||
* Sarven Capadisli, StatusNet, Inc.
|
|
||||||
* Robin Millette, StatusNet, Inc.
|
|
||||||
* Ciaran Gultnieks
|
|
||||||
* Michael Landers
|
|
||||||
* Ori Avtalion
|
|
||||||
* Garret Buell
|
|
||||||
* Mike Cochrane
|
|
||||||
* Matthew Gregg
|
|
||||||
* Florian Biree
|
|
||||||
* Erik Stambaugh
|
|
||||||
* 'drry'
|
|
||||||
* Gina Haeussge
|
|
||||||
* Tryggvi Björgvinsson
|
|
||||||
* Adrian Lang
|
|
||||||
* Ori Avtalion
|
|
||||||
* Meitar Moscovitz
|
|
||||||
* Ken Sheppardson (Trac server, man-about-town)
|
|
||||||
* Tiago 'gouki' Faria (i18n manager)
|
|
||||||
* 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
|
|
||||||
* Siebrand Mazeland and the amazing volunteer translators at translatewiki.net
|
|
||||||
* Brion Vibber, StatusNet, Inc.
|
|
||||||
* James Walker, StatusNet, Inc.
|
|
||||||
* Samantha Doherty, designer, StatusNet, Inc.
|
|
||||||
* Simon Waters, Surevine
|
|
||||||
* Joshua Judson Rosen (rozzin)
|
|
||||||
|
|
||||||
### Extra special thanks to the GNU socialites
|
|
||||||
|
|
||||||
* Craig Andrews
|
|
||||||
* Donald Robertson
|
|
||||||
* Deb Nicholson
|
|
||||||
* Ian Denhart
|
|
||||||
* Steven DuBois
|
|
||||||
* Blaine Cook
|
|
||||||
* Henry Story
|
|
||||||
* Melvin Carvalho
|
|
||||||
|
|
||||||
Thanks also to the developers of our upstream
|
|
||||||
library code and to the thousands of people who
|
|
||||||
have tried out GNU social, told their friends, and
|
|
||||||
built the fediverse network to what it is today.
|
|
||||||
|
|
||||||
### License help from
|
|
||||||
|
|
||||||
* Bradley M. Kuhn
|
|
||||||
|
|
||||||
|
* Matt Lee
|
||||||
|
* Mikael Nordfeldth
|
||||||
|
* Diogo Cordeiro
|
||||||
|
* Bruno Casteleiro
|
||||||
|
* Miguel Dantas
|
||||||
|
* Alexei Sorokin
|
||||||
|
12
TODO.SOCIAL
12
TODO.SOCIAL
@@ -1,12 +0,0 @@
|
|||||||
Things to be done
|
|
||||||
=================
|
|
||||||
|
|
||||||
* Create a theme for GNU social
|
|
||||||
|
|
||||||
* Create a set of plugins to give StatusNet a more social-network UI
|
|
||||||
|
|
||||||
* Work on improvements for annoying things in StatusNet (ie. no
|
|
||||||
redirect to login page when you need to be logged in, etc)
|
|
||||||
|
|
||||||
* Work on adding further Activities, such as sharing photos/video,
|
|
||||||
events, UI for managing relationships.
|
|
@@ -65,7 +65,7 @@ class AddpeopletagAction extends Action
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ class AddpeopletagAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
// Throws exception on error
|
// Throws exception on error
|
||||||
$ptag = Profile_tag::setTag($this->user->id, $this->tagged->id,
|
$ptag = Profile_tag::setTag($this->user->id, $this->tagged->id,
|
||||||
|
@@ -170,12 +170,6 @@ class AllAction extends ShowstreamAction
|
|||||||
}
|
}
|
||||||
$ibs->show();
|
$ibs->show();
|
||||||
}
|
}
|
||||||
// XXX: make this a little more convenient
|
|
||||||
|
|
||||||
if (!common_config('performance', 'high')) {
|
|
||||||
$pop = new InboxTagCloudSection($this, $this->target);
|
|
||||||
$pop->show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -46,7 +46,7 @@ class AllrssAction extends TargetedRss10Action
|
|||||||
{
|
{
|
||||||
protected function getNotices()
|
protected function getNotices()
|
||||||
{
|
{
|
||||||
$stream = new InboxNoticeStream($this->target);
|
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||||
return $stream->getNotices(0, $this->limit)->fetchAll();
|
return $stream->getNotices(0, $this->limit)->fetchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,7 +31,9 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
if (!defined('GNUSOCIAL')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We don't have a rate limit, but some clients check this method.
|
* We don't have a rate limit, but some clients check this method.
|
||||||
@@ -47,62 +49,6 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
*/
|
*/
|
||||||
class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Handle the request
|
|
||||||
*
|
|
||||||
* Return some Twitter-ish data about API limits
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST data (unused)
|
|
||||||
*
|
|
||||||
* @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,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$reset = new DateTime();
|
|
||||||
$reset->modify('+1 hour');
|
|
||||||
|
|
||||||
$this->initDocument($this->format);
|
|
||||||
|
|
||||||
if ($this->format == 'xml') {
|
|
||||||
$this->elementStart('hash');
|
|
||||||
$this->element('remaining-hits', array('type' => 'integer'), 150);
|
|
||||||
$this->element('hourly-limit', array('type' => 'integer'), 150);
|
|
||||||
$this->element(
|
|
||||||
'reset-time', array('type' => 'datetime'),
|
|
||||||
common_date_iso8601($reset->format('r'))
|
|
||||||
);
|
|
||||||
$this->element(
|
|
||||||
'reset_time_in_seconds',
|
|
||||||
array('type' => 'integer'),
|
|
||||||
strtotime('+1 hour')
|
|
||||||
);
|
|
||||||
$this->elementEnd('hash');
|
|
||||||
} elseif ($this->format == 'json') {
|
|
||||||
$out = array(
|
|
||||||
'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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if read only.
|
* Return true if read only.
|
||||||
*
|
*
|
||||||
@@ -112,8 +58,64 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean is read only action?
|
* @return boolean is read only action?
|
||||||
*/
|
*/
|
||||||
function isReadOnly($args)
|
public function isReadOnly($args)
|
||||||
{
|
{
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -54,7 +54,7 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -73,9 +73,9 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if (!in_array($this->format, array('xml', 'json'))) {
|
if (!in_array($this->format, array('xml', 'json'))) {
|
||||||
$this->clientError(
|
$this->clientError(
|
||||||
|
@@ -51,7 +51,7 @@ class ApiAtomServiceAction extends ApiBareAuthAction
|
|||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$this->user = $this->getTargetUser($this->arg('id'));
|
$this->user = $this->getTargetUser($this->arg('id'));
|
||||||
@@ -71,9 +71,9 @@ class ApiAtomServiceAction extends ApiBareAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
header('Content-Type: application/atomsvc+xml');
|
header('Content-Type: application/atomsvc+xml');
|
||||||
|
|
||||||
|
@@ -58,7 +58,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -77,9 +77,9 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
$sitename = common_config('site', 'name');
|
$sitename = common_config('site', 'name');
|
||||||
// TRANS: Message is used as a title when listing the lastest 20 groups. %s is a site name.
|
// TRANS: Message is used as a title when listing the lastest 20 groups. %s is a site name.
|
||||||
|
@@ -28,9 +28,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
|
* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
|
||||||
@@ -44,29 +42,9 @@ if (!defined('STATUSNET')) {
|
|||||||
*/
|
*/
|
||||||
class ApiHelpTestAction extends ApiPrivateAuthAction
|
class ApiHelpTestAction extends ApiPrivateAuthAction
|
||||||
{
|
{
|
||||||
/**
|
protected function handle()
|
||||||
* Take arguments for running
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST args
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
function prepare($args)
|
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::handle();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the request
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST data (unused)
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function handle($args)
|
|
||||||
{
|
|
||||||
parent::handle($args);
|
|
||||||
|
|
||||||
if ($this->format == 'xml') {
|
if ($this->format == 'xml') {
|
||||||
$this->initDocument('xml');
|
$this->initDocument('xml');
|
||||||
@@ -77,12 +55,8 @@ class ApiHelpTestAction extends ApiPrivateAuthAction
|
|||||||
print '"ok"';
|
print '"ok"';
|
||||||
$this->endDocument('json');
|
$this->endDocument('json');
|
||||||
} else {
|
} else {
|
||||||
$this->clientError(
|
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
throw new ClientException(_('API method not found.'), 404);
|
||||||
_('API method not found.'),
|
|
||||||
404,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@ class ApiListSubscriberAction extends ApiBareAuthAction
|
|||||||
{
|
{
|
||||||
var $list = null;
|
var $list = null;
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -52,9 +52,9 @@ class ApiListSubscriberAction extends ApiBareAuthAction
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
$arr = array('profile_tag_id' => $this->list->id,
|
$arr = array('profile_tag_id' => $this->list->id,
|
||||||
'profile_id' => $this->target->id);
|
'profile_id' => $this->target->id);
|
||||||
|
@@ -52,9 +52,9 @@ class ApiOAuthAccessTokenAction extends ApiOAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
$datastore = new ApiGNUsocialOAuthDataStore();
|
$datastore = new ApiGNUsocialOAuthDataStore();
|
||||||
$server = new OAuthServer($datastore);
|
$server = new OAuthServer($datastore);
|
||||||
|
@@ -60,7 +60,7 @@ class ApiOAuthAuthorizeAction extends ApiOAuthAction
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -88,9 +88,9 @@ class ApiOAuthAuthorizeAction extends ApiOAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
|
||||||
|
@@ -49,7 +49,7 @@ class ApiOAuthRequestTokenAction extends ApiOAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -69,9 +69,9 @@ class ApiOAuthRequestTokenAction extends ApiOAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
$datastore = new ApiGNUsocialOAuthDataStore();
|
$datastore = new ApiGNUsocialOAuthDataStore();
|
||||||
$server = new OAuthServer($datastore);
|
$server = new OAuthServer($datastore);
|
||||||
|
@@ -88,7 +88,7 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean success
|
* @return boolean success
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -128,9 +128,9 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
common_debug("In apisearchatom handle()");
|
common_debug("In apisearchatom handle()");
|
||||||
$this->showAtom();
|
$this->showAtom();
|
||||||
}
|
}
|
||||||
@@ -337,21 +337,21 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
|
|||||||
// @todo: Here is where we'd put in a link to an atom feed for threads
|
// @todo: Here is where we'd put in a link to an atom feed for threads
|
||||||
|
|
||||||
$source = null;
|
$source = null;
|
||||||
|
$source_link = null;
|
||||||
|
|
||||||
$ns = $notice->getSource();
|
$ns = $notice->getSource();
|
||||||
if ($ns instanceof Notice_source) {
|
if ($ns instanceof Notice_source) {
|
||||||
if (!empty($ns->name) && !empty($ns->url)) {
|
$source = $ns->code;
|
||||||
$source = '<a href="'
|
if (!empty($ns->url)) {
|
||||||
. htmlspecialchars($ns->url)
|
$source_link = $ns->url;
|
||||||
. '" rel="nofollow">'
|
if (!empty($ns->name)) {
|
||||||
. htmlspecialchars($ns->name)
|
$source = $ns->name;
|
||||||
. '</a>';
|
}
|
||||||
} else {
|
|
||||||
$source = $ns->code;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->element("twitter:source", null, $source);
|
$this->element("twitter:source", null, $source);
|
||||||
|
$this->element("twitter:source_link", null, $source_link);
|
||||||
|
|
||||||
$this->elementStart('author');
|
$this->elementStart('author');
|
||||||
|
|
||||||
|
@@ -57,7 +57,7 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean true if nothing goes wrong
|
* @return boolean true if nothing goes wrong
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -95,9 +95,9 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showResults();
|
$this->showResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -34,9 +34,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes one of the authenticating user's statuses (notices).
|
* Deletes one of the authenticating user's statuses (notices).
|
||||||
@@ -55,87 +53,46 @@ if (!defined('STATUSNET')) {
|
|||||||
*/
|
*/
|
||||||
class ApiStatusesDestroyAction extends ApiAuthAction
|
class ApiStatusesDestroyAction extends ApiAuthAction
|
||||||
{
|
{
|
||||||
var $status = null;
|
protected function prepare(array $args=array())
|
||||||
|
|
||||||
/**
|
|
||||||
* Take arguments for running
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST args
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
function prepare($args)
|
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
$this->user = $this->auth_user;
|
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
|
||||||
$this->notice_id = (int)$this->trimmed('id');
|
// TRANS: Client error displayed trying to delete a status not using POST or DELETE.
|
||||||
|
// TRANS: POST and DELETE should not be translated.
|
||||||
if (empty($notice_id)) {
|
throw new ClientException(_('This method requires a POST or DELETE.'));
|
||||||
$this->notice_id = (int)$this->arg('id');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->notice = Notice::getKV((int)$this->notice_id);
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function handle()
|
||||||
* Handle the request
|
|
||||||
*
|
|
||||||
* Delete the notice and all related replies
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST data (unused)
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function handle($args)
|
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if (!in_array($this->format, array('xml', 'json'))) {
|
if (!$this->scoped->sameAs($this->notice->getProfile()) && !$this->scoped->hasRight(Right::DELETEOTHERSNOTICE)) {
|
||||||
$this->clientError(
|
// TRANS: Client error displayed trying to delete a status of another user.
|
||||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
throw new AuthorizationException(_('You may not delete another user\'s status.'));
|
||||||
_('API method not found.'),
|
|
||||||
404
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
|
if (Event::handle('StartDeleteOwnNotice', array($this->scoped->getUser(), $this->notice))) {
|
||||||
$this->clientError(
|
$this->notice->deleteAs($this->scoped);
|
||||||
// TRANS: Client error displayed trying to delete a status not using POST or DELETE.
|
Event::handle('EndDeleteOwnNotice', array($this->scoped->getUser(), $this->notice));
|
||||||
// TRANS: POST and DELETE should not be translated.
|
|
||||||
_('This method requires a POST or DELETE.'),
|
|
||||||
400,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($this->notice)) {
|
|
||||||
$this->clientError(
|
|
||||||
// TRANS: Client error displayed trying to delete a status with an invalid ID.
|
|
||||||
_('No status found with that ID.'),
|
|
||||||
404, $this->format
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->user->id == $this->notice->profile_id) {
|
|
||||||
if (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) {
|
|
||||||
$this->notice->deleteAs($this->scoped);
|
|
||||||
Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
|
|
||||||
}
|
|
||||||
$this->showNotice();
|
|
||||||
} else {
|
|
||||||
$this->clientError(
|
|
||||||
// TRANS: Client error displayed trying to delete a status of another user.
|
|
||||||
_('You may not delete another user\'s status.'),
|
|
||||||
403,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
$this->showNotice();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -46,7 +46,7 @@
|
|||||||
/api/statuses/update.:format
|
/api/statuses/update.:format
|
||||||
|
|
||||||
@par Formats (:format)
|
@par Formats (:format)
|
||||||
xml, json
|
xml, json, atom
|
||||||
|
|
||||||
@par HTTP Method(s)
|
@par HTTP Method(s)
|
||||||
POST
|
POST
|
||||||
@@ -174,7 +174,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
foreach (array_unique($matches[0]) as $match) {
|
foreach (array_unique($matches[0]) as $match) {
|
||||||
try {
|
try {
|
||||||
$this->media_ids[$match] = File::getByID($match);
|
$this->media_ids[$match] = File::getByID($match);
|
||||||
} catch (EmptyIdException $e) {
|
} catch (EmptyPkeyValueException $e) {
|
||||||
// got a zero from the client, at least Twidere does this on occasion
|
// got a zero from the client, at least Twidere does this on occasion
|
||||||
} catch (NoResultException $e) {
|
} catch (NoResultException $e) {
|
||||||
// File ID was not found. Do we abort and report to the client?
|
// File ID was not found. Do we abort and report to the client?
|
||||||
@@ -339,6 +339,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
$this->showSingleXmlStatus($this->notice);
|
$this->showSingleXmlStatus($this->notice);
|
||||||
} elseif ($this->format == 'json') {
|
} elseif ($this->format == 'json') {
|
||||||
$this->show_single_json_status($this->notice);
|
$this->show_single_json_status($this->notice);
|
||||||
|
} elseif ($this->format == 'atom') {
|
||||||
|
$this->showSingleAtomStatus($this->notice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -92,7 +92,7 @@
|
|||||||
<truncated>false</truncated>
|
<truncated>false</truncated>
|
||||||
<created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
|
<created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
|
||||||
<in_reply_to_status_id/>
|
<in_reply_to_status_id/>
|
||||||
<source><a href="http://code.google.com/p/microblog-purple/">mbpidgin</a></source>
|
<source><a href="http://somesourcecode.net/microblog/">mbpidgin</a></source>
|
||||||
<id>26674201</id>
|
<id>26674201</id>
|
||||||
<in_reply_to_user_id/>
|
<in_reply_to_user_id/>
|
||||||
<in_reply_to_screen_name/>
|
<in_reply_to_screen_name/>
|
||||||
@@ -275,7 +275,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
|||||||
$notices = array();
|
$notices = array();
|
||||||
|
|
||||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||||
|
|
||||||
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
||||||
$this->count,
|
$this->count,
|
||||||
$this->since_id,
|
$this->since_id,
|
||||||
|
@@ -34,7 +34,9 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
if (!defined('GNUSOCIAL')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the most recent notices (default 20) posted by the authenticating
|
* Returns the most recent notices (default 20) posted by the authenticating
|
||||||
@@ -55,9 +57,64 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
*/
|
*/
|
||||||
class ApiTimelineUserAction extends ApiBareAuthAction
|
class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
{
|
{
|
||||||
var $notices = null;
|
public $notices = null;
|
||||||
|
|
||||||
var $next_id = 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
|
* Take arguments for running
|
||||||
@@ -65,8 +122,10 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
* @param array $args $_REQUEST args
|
* @param array $args $_REQUEST args
|
||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
|
* @throws AuthorizationException
|
||||||
|
* @throws ClientException
|
||||||
*/
|
*/
|
||||||
protected function prepare(array $args=array())
|
protected function prepare(array $args = [])
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -86,169 +145,22 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the request
|
|
||||||
*
|
|
||||||
* Just show the notices
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function handle()
|
|
||||||
{
|
|
||||||
parent::handle();
|
|
||||||
|
|
||||||
if ($this->isPost()) {
|
|
||||||
$this->handlePost();
|
|
||||||
} else {
|
|
||||||
$this->showTimeline();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the timeline of notices
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
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 = array();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get notices
|
* Get notices
|
||||||
*
|
*
|
||||||
* @return array notices
|
* @return array notices
|
||||||
*/
|
*/
|
||||||
function getNotices()
|
public function getNotices()
|
||||||
{
|
{
|
||||||
$notices = array();
|
$notices = [];
|
||||||
|
|
||||||
$notice = $this->target->getNotices(($this->page-1) * $this->count,
|
$notice = $this->target->getNotices(
|
||||||
$this->count + 1,
|
($this->page - 1) * $this->count,
|
||||||
$this->since_id,
|
$this->count + 1,
|
||||||
$this->max_id,
|
$this->since_id,
|
||||||
$this->scoped);
|
$this->max_id,
|
||||||
|
$this->scoped
|
||||||
|
);
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
while ($notice->fetch()) {
|
||||||
if (count($notices) < $this->count) {
|
if (count($notices) < $this->count) {
|
||||||
@@ -263,64 +175,29 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
|
* Handle the request
|
||||||
*
|
*
|
||||||
* @param array $args other arguments
|
* Just show the notices
|
||||||
*
|
*
|
||||||
* @return boolean true
|
* @return void
|
||||||
|
* @throws ClientException
|
||||||
|
* @throws ServerException
|
||||||
*/
|
*/
|
||||||
|
protected function handle()
|
||||||
function isReadOnly($args)
|
|
||||||
{
|
{
|
||||||
return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
parent::handle();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if ($this->isPost()) {
|
||||||
* When was this feed last modified?
|
$this->handlePost();
|
||||||
*
|
} else {
|
||||||
* @return string datestamp of the latest notice in the stream
|
$this->showTimeline();
|
||||||
*/
|
|
||||||
function lastModified()
|
|
||||||
{
|
|
||||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
|
||||||
return strtotime($this->notices[0]->created);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function handlePost()
|
||||||
* 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->scoped),
|
|
||||||
common_language(),
|
|
||||||
$this->target->getID(),
|
|
||||||
strtotime($this->notices[0]->created),
|
|
||||||
strtotime($this->notices[$last]->created))
|
|
||||||
)
|
|
||||||
. '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePost()
|
|
||||||
{
|
{
|
||||||
if (!$this->scoped instanceof Profile ||
|
if (!$this->scoped instanceof Profile ||
|
||||||
!$this->target->sameAs($this->scoped)) {
|
!$this->target->sameAs($this->scoped)) {
|
||||||
// TRANS: Client error displayed trying to add a notice to another user's timeline.
|
// 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);
|
$this->clientError(_('Only the user can add to their own timeline.'), 403);
|
||||||
}
|
}
|
||||||
@@ -354,7 +231,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
|
|
||||||
$activity = new Activity($dom->documentElement);
|
$activity = new Activity($dom->documentElement);
|
||||||
|
|
||||||
common_debug('AtomPub: Ignoring right now, but this POST was made to collection: '.$activity->id);
|
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
|
// 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
|
// because we don't let clients set their own UUIDs... Not sure what AtomPub thinks
|
||||||
@@ -375,7 +252,158 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
|
|
||||||
header('HTTP/1.1 201 Created');
|
header('HTTP/1.1 201 Created');
|
||||||
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $stored->getID(),
|
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $stored->getID(),
|
||||||
'format' => 'atom')));
|
'format' => 'atom')));
|
||||||
$this->showSingleAtomStatus($stored);
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -53,7 +53,7 @@ class ApiTrendsAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean false if user doesn't exist
|
* @return boolean false if user doesn't exist
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
return true;
|
return true;
|
||||||
@@ -66,9 +66,9 @@ class ApiTrendsAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showTrends();
|
$this->showTrends();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@ class ApprovegroupAction extends Action
|
|||||||
/**
|
/**
|
||||||
* Prepare to run
|
* Prepare to run
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -139,9 +139,9 @@ class ApprovegroupAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($this->approve) {
|
if ($this->approve) {
|
||||||
|
@@ -50,7 +50,7 @@ class ApprovesubAction extends Action
|
|||||||
/**
|
/**
|
||||||
* Prepare to run
|
* Prepare to run
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -97,9 +97,9 @@ class ApprovesubAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@@ -41,9 +41,8 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
class AttachmentAction extends ManagedAction
|
class AttachmentAction extends ManagedAction
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Attachment object to show
|
* Attachment File object to show
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var $attachment = null;
|
var $attachment = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,14 +59,25 @@ class AttachmentAction extends ManagedAction
|
|||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
if ($id = $this->trimmed('attachment')) {
|
try {
|
||||||
$this->attachment = File::getKV($id);
|
if (!empty($id = $this->trimmed('attachment'))) {
|
||||||
|
$this->attachment = File::getByID($id);
|
||||||
|
} elseif (!empty($filehash = $this->trimmed('filehash'))) {
|
||||||
|
$this->attachment = File::getByHash($filehash);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Not found
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->attachment instanceof File) {
|
if (!$this->attachment instanceof File) {
|
||||||
// TRANS: Client error displayed trying to get a non-existing attachment.
|
// TRANS: Client error displayed trying to get a non-existing attachment.
|
||||||
$this->clientError(_('No such attachment.'), 404);
|
$this->clientError(_('No such attachment.'), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$filename = $this->attachment->getFileOrThumbnailPath();
|
||||||
|
|
||||||
|
if (empty($filename)) {
|
||||||
|
$this->clientError(_('Requested local URL for a file that is not stored locally.'), 404);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,9 +104,9 @@ class AttachmentAction extends ManagedAction
|
|||||||
|
|
||||||
public function showPage()
|
public function showPage()
|
||||||
{
|
{
|
||||||
if (empty($this->attachment->filename)) {
|
if (empty($this->attachment->getFileOrThumbnailPath())) {
|
||||||
// if it's not a local file, gtfo
|
// if it's not a local file, gtfo
|
||||||
common_redirect($this->attachment->url, 303);
|
common_redirect($this->attachment->getUrl(), 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::showPage();
|
parent::showPage();
|
||||||
@@ -132,9 +142,94 @@ class AttachmentAction extends ManagedAction
|
|||||||
function showSections() {
|
function showSections() {
|
||||||
$ns = new AttachmentNoticeSection($this);
|
$ns = new AttachmentNoticeSection($this);
|
||||||
$ns->show();
|
$ns->show();
|
||||||
if (!common_config('performance', 'high')) {
|
}
|
||||||
$atcs = new AttachmentTagCloudSection($this);
|
|
||||||
$atcs->show();
|
/**
|
||||||
|
* Last-modified date for file
|
||||||
|
*
|
||||||
|
* @return int last-modified date as unix timestamp
|
||||||
|
*/
|
||||||
|
public function lastModified()
|
||||||
|
{
|
||||||
|
if (common_config('site', 'use_x_sendfile')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$path = $this->attachment->getFileOrThumbnailPath();
|
||||||
|
if (!empty($path)) {
|
||||||
|
return filemtime($path);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* etag header for file
|
||||||
|
*
|
||||||
|
* This returns the same data (inode, size, mtime) as Apache would,
|
||||||
|
* but in decimal instead of hex.
|
||||||
|
*
|
||||||
|
* @return string etag http header
|
||||||
|
*/
|
||||||
|
function etag()
|
||||||
|
{
|
||||||
|
if (common_config('site', 'use_x_sendfile')) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $this->attachment->getFileOrThumbnailPath();
|
||||||
|
|
||||||
|
$cache = Cache::instance();
|
||||||
|
if($cache) {
|
||||||
|
if (empty($path)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$key = Cache::key('attachments:etag:' . $path);
|
||||||
|
$etag = $cache->get($key);
|
||||||
|
if($etag === false) {
|
||||||
|
$etag = crc32(file_get_contents($path));
|
||||||
|
$cache->set($key,$etag);
|
||||||
|
}
|
||||||
|
return $etag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($path)) {
|
||||||
|
$stat = stat($path);
|
||||||
|
return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include $filepath in the response, for viewing and downloading.
|
||||||
|
* If provided, $filesize is used to size the HTTP request,
|
||||||
|
* otherwise it's value is calculated
|
||||||
|
* @param string $filepath the absolute path to the file to send
|
||||||
|
* @param $filesize optional, calculated if unkown
|
||||||
|
*/
|
||||||
|
static function sendFile(string $filepath, $filesize) {
|
||||||
|
if (is_string(common_config('site', 'x-static-delivery'))) {
|
||||||
|
$tmp = explode(INSTALLDIR, $filepath);
|
||||||
|
$relative_path = end($tmp);
|
||||||
|
common_debug("Using Static Delivery with header: '" .
|
||||||
|
common_config('site', 'x-static-delivery') . ": {$relative_path}'");
|
||||||
|
header(common_config('site', 'x-static-delivery') . ": {$relative_path}");
|
||||||
|
} else {
|
||||||
|
if (empty($filesize)) {
|
||||||
|
$filesize = filesize($filepath);
|
||||||
|
}
|
||||||
|
header("Content-Length: {$filesize}");
|
||||||
|
// header('Cache-Control: private, no-transform, no-store, must-revalidate');
|
||||||
|
|
||||||
|
$ret = @readfile($filepath);
|
||||||
|
|
||||||
|
if ($ret === false) {
|
||||||
|
common_log(LOG_ERR, "Couldn't read file at {$filepath}.");
|
||||||
|
} elseif ($ret !== $filesize) {
|
||||||
|
common_log(LOG_ERR, "The lengths of the file as recorded on the DB (or on disk) for the file " .
|
||||||
|
"{$filepath} differ from what was sent to the user ({$filesize} vs {$ret}).");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
actions/attachment_download.php
Normal file
42
actions/attachment_download.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download notice attachment
|
||||||
|
*
|
||||||
|
* @category Personal
|
||||||
|
* @package GNUsocial
|
||||||
|
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link https:/gnu.io/social
|
||||||
|
*/
|
||||||
|
class Attachment_downloadAction extends AttachmentAction
|
||||||
|
{
|
||||||
|
public function showPage()
|
||||||
|
{
|
||||||
|
// Checks file exists or throws FileNotFoundException
|
||||||
|
$filepath = $this->attachment->getFileOrThumbnailPath();
|
||||||
|
$filesize = $this->attachment->getFileOrThumbnailSize();
|
||||||
|
$mimetype = $this->attachment->getFileOrThumbnailMimetype();
|
||||||
|
|
||||||
|
if (empty($filepath)) {
|
||||||
|
$this->clientError(_('No such attachment'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = MediaFile::getDisplayName($this->attachment);
|
||||||
|
|
||||||
|
// Disable errors, to not mess with the file contents (suppress errors in case access to this
|
||||||
|
// function is blocked, like in some shared hosts). Automatically reset at the end of the
|
||||||
|
// script execution, and we don't want to have any more errors until then, so don't reset it
|
||||||
|
@ini_set('display_errors', 0);
|
||||||
|
|
||||||
|
header("Content-Description: File Transfer");
|
||||||
|
header("Content-Type: {$mimetype}");
|
||||||
|
header("Content-Disposition: attachment; filename=\"{$filename}\"");
|
||||||
|
header('Expires: 0');
|
||||||
|
header('Content-Transfer-Encoding: binary'); // FIXME? Can this be different?
|
||||||
|
|
||||||
|
AttachmentAction::sendFile($filepath, $filesize);
|
||||||
|
}
|
||||||
|
}
|
@@ -53,15 +53,43 @@ class Attachment_thumbnailAction extends AttachmentAction
|
|||||||
$this->thumb_c = $this->boolean('c');
|
$this->thumb_c = $this->boolean('c');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an inline representation of an attachment of the size
|
||||||
|
* requested in the GET variables (read in the constructor). Tries
|
||||||
|
* to send the most appropriate file with the correct size and
|
||||||
|
* headers or displays an error if it's not possible.
|
||||||
|
*/
|
||||||
public function showPage()
|
public function showPage()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Returns a File_thumbnail object or throws exception if not available
|
// Returns a File_thumbnail object or throws exception if not available
|
||||||
try {
|
try {
|
||||||
$thumbnail = $this->attachment->getThumbnail($this->thumb_w, $this->thumb_h, $this->thumb_c);
|
$thumbnail = $this->attachment->getThumbnail($this->thumb_w, $this->thumb_h, $this->thumb_c);
|
||||||
|
$file = $thumbnail->getFile();
|
||||||
} catch (UseFileAsThumbnailException $e) {
|
} catch (UseFileAsThumbnailException $e) {
|
||||||
common_redirect($e->file->getUrl(), 302);
|
// With this exception, the file exists locally
|
||||||
|
$file = $e->file;
|
||||||
|
} catch(FileNotFoundException $e) {
|
||||||
|
$this->clientError(_('No such attachment'), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
common_redirect(File_thumbnail::url($thumbnail->filename), 302);
|
// Checks file exists or throws FileNotFoundException
|
||||||
|
$filepath = $file->getFileOrThumbnailPath($thumbnail);
|
||||||
|
$filesize = $this->attachment->getFileOrThumbnailSize($thumbnail);
|
||||||
|
$mimetype = $file->getFileOrThumbnailMimetype($thumbnail);
|
||||||
|
$filename = MediaFile::getDisplayName($file);
|
||||||
|
|
||||||
|
// Disable errors, to not mess with the file contents (suppress errors in case access to this
|
||||||
|
// function is blocked, like in some shared hosts). Automatically reset at the end of the
|
||||||
|
// script execution, and we don't want to have any more errors until then, so don't reset it
|
||||||
|
@ini_set('display_errors', 0);
|
||||||
|
|
||||||
|
header("Content-Description: File Transfer");
|
||||||
|
header("Content-Type: {$mimetype}");
|
||||||
|
header("Content-Disposition: inline; filename=\"{$filename}\"");
|
||||||
|
header('Expires: 0');
|
||||||
|
header('Content-Transfer-Encoding: binary');
|
||||||
|
|
||||||
|
AttachmentAction::sendFile($filepath, $filesize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
actions/attachment_view.php
Normal file
44
actions/attachment_view.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View notice attachment
|
||||||
|
*
|
||||||
|
* @package GNUsocial
|
||||||
|
* @author Miguel Dantas <biodantasgs@gmail.com>
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
*/
|
||||||
|
class Attachment_viewAction extends AttachmentAction
|
||||||
|
{
|
||||||
|
public function showPage()
|
||||||
|
{
|
||||||
|
// Checks file exists or throws FileNotFoundException
|
||||||
|
$filepath = $this->attachment->getFileOrThumbnailPath();
|
||||||
|
$filesize = $this->attachment->getFileOrThumbnailSize();
|
||||||
|
$mimetype = $this->attachment->getFileOrThumbnailMimetype();
|
||||||
|
|
||||||
|
if (empty($filepath)) {
|
||||||
|
$this->clientError(_('No such attachment'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = MediaFile::getDisplayName($this->attachment);
|
||||||
|
|
||||||
|
// Disable errors, to not mess with the file contents (suppress errors in case access to this
|
||||||
|
// function is blocked, like in some shared hosts). Automatically reset at the end of the
|
||||||
|
// script execution, and we don't want to have any more errors until then, so don't reset it
|
||||||
|
@ini_set('display_errors', 0);
|
||||||
|
|
||||||
|
header("Content-Description: File Transfer");
|
||||||
|
header("Content-Type: {$mimetype}");
|
||||||
|
if (in_array(common_get_mime_media($mimetype), ['image', 'video'])) {
|
||||||
|
header("Content-Disposition: inline; filename=\"{$filename}\"");
|
||||||
|
} else {
|
||||||
|
header("Content-Disposition: attachment; filename=\"{$filename}\"");
|
||||||
|
}
|
||||||
|
header('Expires: 0');
|
||||||
|
header('Content-Transfer-Encoding: binary');
|
||||||
|
|
||||||
|
AttachmentAction::sendFile($filepath, $filesize);
|
||||||
|
}
|
||||||
|
}
|
@@ -49,6 +49,20 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
var $imagefile = null;
|
var $imagefile = null;
|
||||||
var $filename = null;
|
var $filename = null;
|
||||||
|
|
||||||
|
function prepare(array $args=array())
|
||||||
|
{
|
||||||
|
$avatarpath = Avatar::path('');
|
||||||
|
|
||||||
|
if (!is_writable($avatarpath)) {
|
||||||
|
throw new Exception(_("The administrator of your site needs to
|
||||||
|
add write permissions on the avatar upload folder before
|
||||||
|
you're able to set one."));
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::prepare($args);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title of the page
|
* Title of the page
|
||||||
*
|
*
|
||||||
@@ -92,16 +106,6 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
|
|
||||||
function showUploadForm()
|
function showUploadForm()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$profile = $user->getProfile();
|
|
||||||
|
|
||||||
if (!$profile) {
|
|
||||||
common_log_db_error($user, 'SELECT', __FILE__);
|
|
||||||
// TRANS: Error message displayed when referring to a user without a profile.
|
|
||||||
$this->serverError(_('User has no profile.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementStart('form', array('enctype' => 'multipart/form-data',
|
$this->elementStart('form', array('enctype' => 'multipart/form-data',
|
||||||
'method' => 'post',
|
'method' => 'post',
|
||||||
'id' => 'form_settings_avatar',
|
'id' => 'form_settings_avatar',
|
||||||
@@ -116,7 +120,7 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
if (Event::handle('StartAvatarFormData', array($this))) {
|
if (Event::handle('StartAvatarFormData', array($this))) {
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
try {
|
try {
|
||||||
$original = Avatar::getUploaded($profile);
|
$original = Avatar::getUploaded($this->scoped);
|
||||||
|
|
||||||
$this->elementStart('li', array('id' => 'avatar_original',
|
$this->elementStart('li', array('id' => 'avatar_original',
|
||||||
'class' => 'avatar_view'));
|
'class' => 'avatar_view'));
|
||||||
@@ -126,7 +130,7 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
$this->element('img', array('src' => $original->displayUrl(),
|
$this->element('img', array('src' => $original->displayUrl(),
|
||||||
'width' => $original->width,
|
'width' => $original->width,
|
||||||
'height' => $original->height,
|
'height' => $original->height,
|
||||||
'alt' => $user->nickname));
|
'alt' => $this->scoped->getNickname()));
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
} catch (NoAvatarException $e) {
|
} catch (NoAvatarException $e) {
|
||||||
@@ -134,7 +138,7 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
$avatar = $this->scoped->getAvatar(AVATAR_PROFILE_SIZE);
|
||||||
$this->elementStart('li', array('id' => 'avatar_preview',
|
$this->elementStart('li', array('id' => 'avatar_preview',
|
||||||
'class' => 'avatar_view'));
|
'class' => 'avatar_view'));
|
||||||
// TRANS: Header on avatar upload page for thumbnail of to be used rendition of uploaded avatar (h2).
|
// TRANS: Header on avatar upload page for thumbnail of to be used rendition of uploaded avatar (h2).
|
||||||
@@ -143,7 +147,7 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
$this->element('img', array('src' => $avatar->displayUrl(),
|
$this->element('img', array('src' => $avatar->displayUrl(),
|
||||||
'width' => AVATAR_PROFILE_SIZE,
|
'width' => AVATAR_PROFILE_SIZE,
|
||||||
'height' => AVATAR_PROFILE_SIZE,
|
'height' => AVATAR_PROFILE_SIZE,
|
||||||
'alt' => $user->nickname));
|
'alt' => $this->scoped->getNickname()));
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
if (!empty($avatar->filename)) {
|
if (!empty($avatar->filename)) {
|
||||||
// TRANS: Button on avatar upload page to delete current avatar.
|
// TRANS: Button on avatar upload page to delete current avatar.
|
||||||
@@ -180,16 +184,6 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
|
|
||||||
function showCropForm()
|
function showCropForm()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$profile = $user->getProfile();
|
|
||||||
|
|
||||||
if (!$profile) {
|
|
||||||
common_log_db_error($user, 'SELECT', __FILE__);
|
|
||||||
// TRANS: Error message displayed when referring to a user without a profile.
|
|
||||||
$this->serverError(_('User has no profile.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementStart('form', array('method' => 'post',
|
$this->elementStart('form', array('method' => 'post',
|
||||||
'id' => 'form_settings_avatar',
|
'id' => 'form_settings_avatar',
|
||||||
'class' => 'form_settings',
|
'class' => 'form_settings',
|
||||||
@@ -211,7 +205,7 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
$this->element('img', array('src' => Avatar::url($this->filedata['filename']),
|
$this->element('img', array('src' => Avatar::url($this->filedata['filename']),
|
||||||
'width' => $this->filedata['width'],
|
'width' => $this->filedata['width'],
|
||||||
'height' => $this->filedata['height'],
|
'height' => $this->filedata['height'],
|
||||||
'alt' => $user->nickname));
|
'alt' => $this->scoped->getNickname()));
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
|
||||||
@@ -224,7 +218,7 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
$this->element('img', array('src' => Avatar::url($this->filedata['filename']),
|
$this->element('img', array('src' => Avatar::url($this->filedata['filename']),
|
||||||
'width' => AVATAR_PROFILE_SIZE,
|
'width' => AVATAR_PROFILE_SIZE,
|
||||||
'height' => AVATAR_PROFILE_SIZE,
|
'height' => AVATAR_PROFILE_SIZE,
|
||||||
'alt' => $user->nickname));
|
'alt' => $this->scoped->getNickname()));
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
|
|
||||||
foreach (array('avatar_crop_x', 'avatar_crop_y',
|
foreach (array('avatar_crop_x', 'avatar_crop_y',
|
||||||
|
@@ -74,6 +74,9 @@ class BackupaccountAction extends FormAction
|
|||||||
// @fixme atom feed logic is in getString...
|
// @fixme atom feed logic is in getString...
|
||||||
// but we just want it to output to the outputter.
|
// but we just want it to output to the outputter.
|
||||||
$this->raw($stream->getString());
|
$this->raw($stream->getString());
|
||||||
|
|
||||||
|
// Don't print the page HTML
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isReadOnly($args) {
|
public function isReadOnly($args) {
|
||||||
|
@@ -53,7 +53,7 @@ class BlockAction extends ProfileFormAction
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
if (!parent::prepare($args)) {
|
if (!parent::prepare($args)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -78,7 +78,7 @@ class BlockAction extends ProfileFormAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
if ($this->arg('no')) {
|
if ($this->arg('no')) {
|
||||||
|
@@ -151,7 +151,7 @@ class GroupBlockList extends ProfileList
|
|||||||
$this->group = $group;
|
$this->group = $group;
|
||||||
}
|
}
|
||||||
|
|
||||||
function newListItem($profile)
|
function newListItem(Profile $profile)
|
||||||
{
|
{
|
||||||
return new GroupBlockListItem($profile, $this->group, $this->action);
|
return new GroupBlockListItem($profile, $this->group, $this->action);
|
||||||
}
|
}
|
||||||
|
@@ -50,7 +50,7 @@ class CancelgroupAction extends Action
|
|||||||
/**
|
/**
|
||||||
* Prepare to run
|
* Prepare to run
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -127,9 +127,9 @@ class CancelgroupAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->request->abort();
|
$this->request->abort();
|
||||||
|
@@ -27,9 +27,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Confirm an address
|
* Confirm an address
|
||||||
@@ -44,25 +42,14 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
class ConfirmaddressAction extends Action
|
class ConfirmaddressAction extends ManagedAction
|
||||||
{
|
{
|
||||||
/** type of confirmation. */
|
/** type of confirmation. */
|
||||||
|
|
||||||
var $address;
|
protected $address;
|
||||||
|
|
||||||
/**
|
protected function doPreparation()
|
||||||
* Accept a confirmation code
|
|
||||||
*
|
|
||||||
* Checks the code and confirms the address in the
|
|
||||||
* user record
|
|
||||||
*
|
|
||||||
* @param args $args $_REQUEST array
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function handle($args)
|
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
|
||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
common_set_returnto($this->selfUrl());
|
common_set_returnto($this->selfUrl());
|
||||||
common_redirect(common_local_url('login'));
|
common_redirect(common_local_url('login'));
|
||||||
@@ -70,32 +57,45 @@ class ConfirmaddressAction extends Action
|
|||||||
$code = $this->trimmed('code');
|
$code = $this->trimmed('code');
|
||||||
if (!$code) {
|
if (!$code) {
|
||||||
// TRANS: Client error displayed when not providing a confirmation code in the contact address confirmation action.
|
// TRANS: Client error displayed when not providing a confirmation code in the contact address confirmation action.
|
||||||
$this->clientError(_('No confirmation code.'));
|
throw new ClientException(_('No confirmation code.'));
|
||||||
}
|
}
|
||||||
$confirm = Confirm_address::getKV('code', $code);
|
$confirm = Confirm_address::getKV('code', $code);
|
||||||
if (!$confirm) {
|
if (!$confirm instanceof Confirm_address) {
|
||||||
// TRANS: Client error displayed when providing a non-existing confirmation code in the contact address confirmation action.
|
// TRANS: Client error displayed when providing a non-existing confirmation code in the contact address confirmation action.
|
||||||
$this->clientError(_('Confirmation code not found.'));
|
throw new ClientException(_('Confirmation code not found.'), 404);
|
||||||
}
|
}
|
||||||
$cur = common_current_user();
|
|
||||||
if ($cur->id != $confirm->user_id) {
|
try {
|
||||||
|
$profile = Profile::getByID($confirm->user_id);
|
||||||
|
} catch (NoResultException $e) {
|
||||||
|
common_log(LOG_INFO, 'Tried to confirm the email for a deleted profile: '._ve(['id'=>$confirm->user_id, 'email'=>$confirm->address]));
|
||||||
|
$confirm->delete();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
if (!$profile->sameAs($this->scoped)) {
|
||||||
// TRANS: Client error displayed when not providing a confirmation code for another user in the contact address confirmation action.
|
// TRANS: Client error displayed when not providing a confirmation code for another user in the contact address confirmation action.
|
||||||
$this->clientError(_('That confirmation code is not for you!'));
|
throw new AuthorizationException(_('That confirmation code is not for you!'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = $confirm->address_type;
|
$type = $confirm->address_type;
|
||||||
$transports = array();
|
$transports = array();
|
||||||
Event::handle('GetImTransports', array(&$transports));
|
Event::handle('GetImTransports', array(&$transports));
|
||||||
if (!in_array($type, array('email', 'sms')) && !in_array($type, array_keys($transports))) {
|
if (!in_array($type, array('email', 'sms')) && !in_array($type, array_keys($transports))) {
|
||||||
// TRANS: Server error for an unknown address type, which can be 'email', 'sms', or the name of an IM network (such as 'xmpp' or 'aim')
|
// TRANS: Server error for an unknown address type, which can be 'email', 'sms', or the name of an IM network (such as 'xmpp' or 'aim')
|
||||||
$this->serverError(sprintf(_('Unrecognized address type %s'), $type));
|
throw new ServerException(sprintf(_('Unrecognized address type %s'), $type));
|
||||||
}
|
}
|
||||||
$this->address = $confirm->address;
|
$this->address = $confirm->address;
|
||||||
|
|
||||||
|
$cur = $this->scoped->getUser();
|
||||||
|
|
||||||
$cur->query('BEGIN');
|
$cur->query('BEGIN');
|
||||||
if (in_array($type, array('email', 'sms')))
|
if (in_array($type, array('email', 'sms'))) {
|
||||||
{
|
common_debug("Confirming {$type} address for user {$this->scoped->getID()}");
|
||||||
if ($cur->$type == $confirm->address) {
|
if ($cur->$type == $confirm->address) {
|
||||||
|
// Already verified, so delete the confirm_address entry
|
||||||
|
$confirm->delete();
|
||||||
// TRANS: Client error for an already confirmed email/jabber/sms address.
|
// TRANS: Client error for an already confirmed email/jabber/sms address.
|
||||||
$this->clientError(_('That address has already been confirmed.'));
|
throw new AlreadyFulfilledException(_('That address has already been confirmed.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$orig_user = clone($cur);
|
$orig_user = clone($cur);
|
||||||
@@ -122,44 +122,39 @@ class ConfirmaddressAction extends Action
|
|||||||
$user_im_prefs->user_id = $cur->id;
|
$user_im_prefs->user_id = $cur->id;
|
||||||
if ($user_im_prefs->find() && $user_im_prefs->fetch()) {
|
if ($user_im_prefs->find() && $user_im_prefs->fetch()) {
|
||||||
if($user_im_prefs->screenname == $confirm->address){
|
if($user_im_prefs->screenname == $confirm->address){
|
||||||
|
// Already verified, so delete the confirm_address entry
|
||||||
|
$confirm->delete();
|
||||||
// TRANS: Client error for an already confirmed IM address.
|
// TRANS: Client error for an already confirmed IM address.
|
||||||
$this->clientError(_('That address has already been confirmed.'));
|
throw new AlreadyFulfilledException(_('That address has already been confirmed.'));
|
||||||
}
|
}
|
||||||
$user_im_prefs->screenname = $confirm->address;
|
$user_im_prefs->screenname = $confirm->address;
|
||||||
$result = $user_im_prefs->update();
|
$result = $user_im_prefs->update();
|
||||||
|
|
||||||
if (!$result) {
|
if ($result === false) {
|
||||||
common_log_db_error($user_im_prefs, 'UPDATE', __FILE__);
|
common_log_db_error($user_im_prefs, 'UPDATE', __FILE__);
|
||||||
// TRANS: Server error displayed when updating IM preferences fails.
|
// TRANS: Server error displayed when updating IM preferences fails.
|
||||||
$this->serverError(_('Could not update user IM preferences.'));
|
throw new ServerException(_('Could not update user IM preferences.'));
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
$user_im_prefs = new User_im_prefs();
|
$user_im_prefs = new User_im_prefs();
|
||||||
$user_im_prefs->screenname = $confirm->address;
|
$user_im_prefs->screenname = $confirm->address;
|
||||||
$user_im_prefs->transport = $confirm->address_type;
|
$user_im_prefs->transport = $confirm->address_type;
|
||||||
$user_im_prefs->user_id = $cur->id;
|
$user_im_prefs->user_id = $cur->id;
|
||||||
|
$user_im_prefs->created = common_sql_now();
|
||||||
$result = $user_im_prefs->insert();
|
$result = $user_im_prefs->insert();
|
||||||
|
|
||||||
if (!$result) {
|
if ($result === false) {
|
||||||
common_log_db_error($user_im_prefs, 'INSERT', __FILE__);
|
common_log_db_error($user_im_prefs, 'INSERT', __FILE__);
|
||||||
// TRANS: Server error displayed when adding IM preferences fails.
|
// TRANS: Server error displayed when adding IM preferences fails.
|
||||||
$this->serverError(_('Could not insert user IM preferences.'));
|
throw new ServerException(_('Could not insert user IM preferences.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $confirm->delete();
|
$confirm->delete();
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
common_log_db_error($confirm, 'DELETE', __FILE__);
|
|
||||||
// TRANS: Server error displayed when an address confirmation code deletion from the
|
|
||||||
// TRANS: database fails in the contact address confirmation action.
|
|
||||||
$this->serverError(_('Could not delete address confirmation.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$cur->query('COMMIT');
|
$cur->query('COMMIT');
|
||||||
$this->showPage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,8 +175,6 @@ class ConfirmaddressAction extends Action
|
|||||||
*/
|
*/
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$cur = common_current_user();
|
|
||||||
|
|
||||||
$this->element('p', null,
|
$this->element('p', null,
|
||||||
// TRANS: Success message for the contact address confirmation action.
|
// TRANS: Success message for the contact address confirmation action.
|
||||||
// TRANS: %s can be 'email', 'jabber', or 'sms'.
|
// TRANS: %s can be 'email', 'jabber', or 'sms'.
|
||||||
|
@@ -28,7 +28,9 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
if (!defined('GNUSOCIAL')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversation tree in the browser
|
* Conversation tree in the browser
|
||||||
@@ -45,9 +47,11 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
*/
|
*/
|
||||||
class ConversationAction extends ManagedAction
|
class ConversationAction extends ManagedAction
|
||||||
{
|
{
|
||||||
var $conv = null;
|
protected $redirectAfterLogin = true;
|
||||||
var $page = null;
|
|
||||||
var $notices = null;
|
public $conv = null;
|
||||||
|
public $page = null;
|
||||||
|
public $notices = null;
|
||||||
|
|
||||||
protected function doPreparation()
|
protected function doPreparation()
|
||||||
{
|
{
|
||||||
@@ -59,7 +63,7 @@ class ConversationAction extends ManagedAction
|
|||||||
*
|
*
|
||||||
* @return string page title
|
* @return string page title
|
||||||
*/
|
*/
|
||||||
function title()
|
public function title()
|
||||||
{
|
{
|
||||||
// TRANS: Title for page with a conversion (multiple notices in context).
|
// TRANS: Title for page with a conversion (multiple notices in context).
|
||||||
return _('Conversation');
|
return _('Conversation');
|
||||||
@@ -72,48 +76,48 @@ class ConversationAction extends ManagedAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function showContent()
|
public function showContent()
|
||||||
{
|
{
|
||||||
if (Event::handle('StartShowConversation', array($this, $this->conv, $this->scoped))) {
|
if (Event::handle('StartShowConversation', [$this, $this->conv, $this->scoped])) {
|
||||||
$notices = $this->conv->getNotices($this->scoped);
|
$notices = $this->conv->getNotices($this->scoped);
|
||||||
$nl = new FullThreadedNoticeList($notices, $this, $this->scoped);
|
$nl = new FullThreadedNoticeList($notices, $this, $this->scoped);
|
||||||
$cnt = $nl->show();
|
$cnt = $nl->show();
|
||||||
}
|
}
|
||||||
Event::handle('EndShowConversation', array($this, $this->conv, $this->scoped));
|
Event::handle('EndShowConversation', [$this, $this->conv, $this->scoped]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isReadOnly($args)
|
public function isReadOnly($args)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFeeds()
|
public function getFeeds()
|
||||||
{
|
{
|
||||||
|
return [
|
||||||
return array(new Feed(Feed::JSON,
|
new Feed(Feed::JSON,
|
||||||
common_local_url('apiconversation',
|
common_local_url('apiconversation',
|
||||||
array(
|
['id' => $this->conv->getID(),
|
||||||
'id' => $this->conv->getID(),
|
'format' => 'as']),
|
||||||
'format' => 'as')),
|
// TRANS: Title for link to notice feed.
|
||||||
// TRANS: Title for link to notice feed.
|
// TRANS: %s is a user nickname.
|
||||||
// TRANS: %s is a user nickname.
|
_('Conversation feed (Activity Streams JSON)')
|
||||||
_('Conversation feed (Activity Streams JSON)')),
|
),
|
||||||
new Feed(Feed::RSS2,
|
new Feed(Feed::RSS2,
|
||||||
common_local_url('apiconversation',
|
common_local_url('apiconversation',
|
||||||
array(
|
['id' => $this->conv->getID(),
|
||||||
'id' => $this->conv->getID(),
|
'format' => 'rss']),
|
||||||
'format' => 'rss')),
|
// TRANS: Title for link to notice feed.
|
||||||
// TRANS: Title for link to notice feed.
|
// TRANS: %s is a user nickname.
|
||||||
// TRANS: %s is a user nickname.
|
_('Conversation feed (RSS 2.0)')
|
||||||
_('Conversation feed (RSS 2.0)')),
|
),
|
||||||
new Feed(Feed::ATOM,
|
new Feed(Feed::ATOM,
|
||||||
common_local_url('apiconversation',
|
common_local_url('apiconversation',
|
||||||
array(
|
['id' => $this->conv->getID(),
|
||||||
'id' => $this->conv->getID(),
|
'format' => 'atom']),
|
||||||
'format' => 'atom')),
|
// TRANS: Title for link to notice feed.
|
||||||
// TRANS: Title for link to notice feed.
|
// TRANS: %s is a user nickname.
|
||||||
// TRANS: %s is a user nickname.
|
_('Conversation feed (Atom)')
|
||||||
_('Conversation feed (Atom)')));
|
)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -51,25 +51,25 @@ if (!defined('STATUSNET')) {
|
|||||||
class DeleteaccountAction extends Action
|
class DeleteaccountAction extends Action
|
||||||
{
|
{
|
||||||
private $_complete = false;
|
private $_complete = false;
|
||||||
private $_error = null;
|
private $_error = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For initializing members of the class.
|
* For initializing members of the class.
|
||||||
*
|
*
|
||||||
* @param array $argarray misc. arguments
|
* @param array $args misc. arguments
|
||||||
*
|
*
|
||||||
* @return boolean true
|
* @return boolean true
|
||||||
|
* @throws ClientException
|
||||||
*/
|
*/
|
||||||
function prepare($argarray)
|
function prepare(array $args = [])
|
||||||
{
|
{
|
||||||
parent::prepare($argarray);
|
parent::prepare($args);
|
||||||
|
|
||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
|
|
||||||
if (empty($cur)) {
|
if (empty($cur)) {
|
||||||
// TRANS: Client exception displayed trying to delete a user account while not logged in.
|
// TRANS: Client exception displayed trying to delete a user account while not logged in.
|
||||||
throw new ClientException(_("Only logged-in users ".
|
throw new ClientException(_("Only logged-in users can delete their account."), 403);
|
||||||
"can delete their account."), 403);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$cur->hasRight(Right::DELETEACCOUNT)) {
|
if (!$cur->hasRight(Right::DELETEACCOUNT)) {
|
||||||
@@ -83,20 +83,71 @@ class DeleteaccountAction extends Action
|
|||||||
/**
|
/**
|
||||||
* Handler method
|
* Handler method
|
||||||
*
|
*
|
||||||
* @param array $argarray is ignored since it's now passed in in prepare()
|
|
||||||
*
|
|
||||||
* @return void
|
* @return void
|
||||||
|
* @throws AuthorizationException
|
||||||
|
* @throws ServerException
|
||||||
*/
|
*/
|
||||||
function handle($argarray=null)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($argarray);
|
parent::handle();
|
||||||
|
|
||||||
if ($this->isPost()) {
|
if ($this->isPost()) {
|
||||||
$this->deleteAccount();
|
$this->deleteAccount();
|
||||||
} else {
|
} else {
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the current user's account
|
||||||
|
*
|
||||||
|
* Checks for the "I am sure." string to make sure the user really
|
||||||
|
* wants to delete their account.
|
||||||
|
*
|
||||||
|
* Then, marks the account as deleted and begins the deletion process
|
||||||
|
* (actually done by a back-end handler).
|
||||||
|
*
|
||||||
|
* If successful it logs the user out, and shows a brief completion message.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws AuthorizationException
|
||||||
|
* @throws ServerException
|
||||||
|
*/
|
||||||
|
function deleteAccount()
|
||||||
|
{
|
||||||
|
$this->checkSessionToken();
|
||||||
|
// !!! If this string is changed, it also needs to be changed in DeleteAccountForm::formData()
|
||||||
|
// TRANS: Confirmation text for user deletion. The user has to type this exactly the same, including punctuation.
|
||||||
|
$iamsure = _('I am sure.');
|
||||||
|
if ($this->trimmed('iamsure') != $iamsure) {
|
||||||
|
// TRANS: Notification for user about the text that must be input to be able to delete a user account.
|
||||||
|
// TRANS: %s is the text that needs to be input.
|
||||||
|
$this->_error = sprintf(_('You must write "%s" exactly in the box.'), $iamsure);
|
||||||
|
$this->showPage();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cur = common_current_user();
|
||||||
|
|
||||||
|
// Mark the account as deleted and shove low-level deletion tasks
|
||||||
|
// to background queues. Removing a lot of posts can take a while...
|
||||||
|
|
||||||
|
if (!$cur->hasRole(Profile_role::DELETED)) {
|
||||||
|
$cur->grantRole(Profile_role::DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
$qm = QueueManager::get();
|
||||||
|
$qm->enqueue($cur, 'deluser');
|
||||||
|
|
||||||
|
// The user is really-truly logged out
|
||||||
|
|
||||||
|
common_set_user(null);
|
||||||
|
common_real_login(false); // not logged in
|
||||||
|
common_forgetme(); // don't log back in!
|
||||||
|
|
||||||
|
$this->_complete = true;
|
||||||
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,55 +190,6 @@ class DeleteaccountAction extends Action
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the current user's account
|
|
||||||
*
|
|
||||||
* Checks for the "I am sure." string to make sure the user really
|
|
||||||
* wants to delete their account.
|
|
||||||
*
|
|
||||||
* Then, marks the account as deleted and begins the deletion process
|
|
||||||
* (actually done by a back-end handler).
|
|
||||||
*
|
|
||||||
* If successful it logs the user out, and shows a brief completion message.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function deleteAccount()
|
|
||||||
{
|
|
||||||
$this->checkSessionToken();
|
|
||||||
// !!! If this string is changed, it also needs to be changed in DeleteAccountForm::formData()
|
|
||||||
// TRANS: Confirmation text for user deletion. The user has to type this exactly the same, including punctuation.
|
|
||||||
$iamsure = _('I am sure.');
|
|
||||||
if ($this->trimmed('iamsure') != $iamsure ) {
|
|
||||||
// TRANS: Notification for user about the text that must be input to be able to delete a user account.
|
|
||||||
// TRANS: %s is the text that needs to be input.
|
|
||||||
$this->_error = sprintf(_('You must write "%s" exactly in the box.'), $iamsure);
|
|
||||||
$this->showPage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cur = common_current_user();
|
|
||||||
|
|
||||||
// Mark the account as deleted and shove low-level deletion tasks
|
|
||||||
// to background queues. Removing a lot of posts can take a while...
|
|
||||||
|
|
||||||
if (!$cur->hasRole(Profile_role::DELETED)) {
|
|
||||||
$cur->grantRole(Profile_role::DELETED);
|
|
||||||
}
|
|
||||||
|
|
||||||
$qm = QueueManager::get();
|
|
||||||
$qm->enqueue($cur, 'deluser');
|
|
||||||
|
|
||||||
// The user is really-truly logged out
|
|
||||||
|
|
||||||
common_set_user(null);
|
|
||||||
common_real_login(false); // not logged in
|
|
||||||
common_forgetme(); // don't log back in!
|
|
||||||
|
|
||||||
$this->_complete = true;
|
|
||||||
$this->showPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the page content.
|
* Shows the page content.
|
||||||
*
|
*
|
||||||
@@ -202,9 +204,9 @@ class DeleteaccountAction extends Action
|
|||||||
{
|
{
|
||||||
if ($this->_complete) {
|
if ($this->_complete) {
|
||||||
$this->element('p', 'confirmation',
|
$this->element('p', 'confirmation',
|
||||||
// TRANS: Confirmation that a user account has been deleted.
|
// TRANS: Confirmation that a user account has been deleted.
|
||||||
_('Account deleted.'));
|
_('Account deleted.'));
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($this->_error)) {
|
if (!empty($this->_error)) {
|
||||||
@@ -276,16 +278,13 @@ class DeleteAccountForm extends Form
|
|||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
|
|
||||||
// TRANS: Form text for user deletion form.
|
// TRANS: Form text for user deletion form.
|
||||||
$msg = '<p>' . _('This will <strong>permanently delete</strong> '.
|
$msg = '<p>' . _('This will <strong>permanently delete</strong> your account data from this server.') . '</p>';
|
||||||
'your account data from this server.') . '</p>';
|
|
||||||
|
|
||||||
if ($cur->hasRight(Right::BACKUPACCOUNT)) {
|
if ($cur->hasRight(Right::BACKUPACCOUNT)) {
|
||||||
// TRANS: Additional form text for user deletion form shown if a user has account backup rights.
|
// TRANS: Additional form text for user deletion form shown if a user has account backup rights.
|
||||||
// TRANS: %s is a URL to the backup page.
|
// TRANS: %s is a URL to the backup page.
|
||||||
$msg .= '<p>' . sprintf(_('You are strongly advised to '.
|
$msg .= '<p>' . sprintf(_('You are strongly advised to <a href="%s">back up your data</a> before deletion.'),
|
||||||
'<a href="%s">back up your data</a>'.
|
common_local_url('backupaccount')) . '</p>';
|
||||||
' before deletion.'),
|
|
||||||
common_local_url('backupaccount')) . '</p>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementStart('p');
|
$this->out->elementStart('p');
|
||||||
@@ -296,13 +295,13 @@ class DeleteAccountForm extends Form
|
|||||||
// TRANS: Confirmation text for user deletion. The user has to type this exactly the same, including punctuation.
|
// TRANS: Confirmation text for user deletion. The user has to type this exactly the same, including punctuation.
|
||||||
$iamsure = _("I am sure.");
|
$iamsure = _("I am sure.");
|
||||||
$this->out->input('iamsure',
|
$this->out->input('iamsure',
|
||||||
// TRANS: Field label for delete account confirmation entry.
|
// TRANS: Field label for delete account confirmation entry.
|
||||||
_('Confirm'),
|
_('Confirm'),
|
||||||
null,
|
null,
|
||||||
// TRANS: Input title for the delete account field.
|
// TRANS: Input title for the delete account field.
|
||||||
// TRANS: %s is the text that needs to be input.
|
// TRANS: %s is the text that needs to be input.
|
||||||
sprintf(_('Enter "%s" to confirm that '.
|
sprintf(_('Enter "%s" to confirm that ' .
|
||||||
'you want to delete your account.'),$iamsure ));
|
'you want to delete your account.'), $iamsure));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -315,11 +314,11 @@ class DeleteAccountForm extends Form
|
|||||||
function formActions()
|
function formActions()
|
||||||
{
|
{
|
||||||
$this->out->submit('submit',
|
$this->out->submit('submit',
|
||||||
// TRANS: Button text for user account deletion.
|
// TRANS: Button text for user account deletion.
|
||||||
_m('BUTTON', 'Delete'),
|
_m('BUTTON', 'Delete'),
|
||||||
'submit',
|
'submit',
|
||||||
null,
|
null,
|
||||||
// TRANS: Button title for user account deletion.
|
// TRANS: Button title for user account deletion.
|
||||||
_('Permanently delete your account.'));
|
_('Permanently delete your account.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -51,7 +51,7 @@ class DeleteapplicationAction extends Action
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
if (!parent::prepare($args)) {
|
if (!parent::prepare($args)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -89,7 +89,7 @@ class DeleteapplicationAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
|
||||||
|
@@ -55,7 +55,7 @@ class DeletegroupAction extends RedirectingAction
|
|||||||
* @fixme merge common setup code with other group actions
|
* @fixme merge common setup code with other group actions
|
||||||
* @fixme allow group admins to delete their own groups
|
* @fixme allow group admins to delete their own groups
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -114,9 +114,9 @@ class DeletegroupAction extends RedirectingAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
if ($this->arg('no')) {
|
if ($this->arg('no')) {
|
||||||
$this->returnToPrevious();
|
$this->returnToPrevious();
|
||||||
|
@@ -39,9 +39,10 @@ class DeletenoticeAction extends FormAction
|
|||||||
{
|
{
|
||||||
$this->notice = Notice::getByID($this->trimmed('notice'));
|
$this->notice = Notice::getByID($this->trimmed('notice'));
|
||||||
|
|
||||||
if (!$this->scoped->sameAs($this->notice->getProfile()) &&
|
if ($this->notice->isVerb([ActivityVerb::DELETE]) ||
|
||||||
!$this->scoped->hasRight(Right::DELETEOTHERSNOTICE)) {
|
(!$this->scoped->sameAs($this->notice->getProfile()) &&
|
||||||
// TRANS: Error message displayed trying to delete a notice that was not made by the current user.
|
!$this->scoped->hasRight(Right::DELETEOTHERSNOTICE))) {
|
||||||
|
// TRANS: Error message displayed when trying to delete a notice that was not made by the current user.
|
||||||
$this->clientError(_('Cannot delete this notice.'));
|
$this->clientError(_('Cannot delete this notice.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -80,7 +80,7 @@ class DeleteuserAction extends ProfileFormAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
if ($this->arg('no')) {
|
if ($this->arg('no')) {
|
||||||
|
@@ -57,7 +57,7 @@ class EditApplicationAction extends Action
|
|||||||
/**
|
/**
|
||||||
* Prepare to run
|
* Prepare to run
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -94,9 +94,9 @@ class EditApplicationAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
$this->handlePost($args);
|
$this->handlePost($args);
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('STATUSNET') && !defined('LACONICA') && !defined('GNUSOCIAL')) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,24 +42,63 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @author Zach Copley <zach@status.net>
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @author Alexei Sorokin <sor.alexei@meowr.ru>
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
class EditgroupAction extends GroupAction
|
class EditgroupAction extends GroupAction
|
||||||
{
|
{
|
||||||
var $msg;
|
public $message = null;
|
||||||
|
public $success = null;
|
||||||
|
protected $canPost = true;
|
||||||
|
|
||||||
function title()
|
public function title()
|
||||||
{
|
{
|
||||||
// TRANS: Title for form to edit a group. %s is a group nickname.
|
// TRANS: Title for form to edit a group. %s is a group nickname.
|
||||||
return sprintf(_('Edit %s group'), $this->group->nickname);
|
return sprintf(_('Edit %s group'), $this->group->nickname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function showContent()
|
||||||
|
{
|
||||||
|
$form = new GroupEditForm($this, $this->group);
|
||||||
|
$form->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showPageNoticeBlock()
|
||||||
|
{
|
||||||
|
parent::showPageNoticeBlock();
|
||||||
|
|
||||||
|
if ($this->message) {
|
||||||
|
$this->element(
|
||||||
|
'p',
|
||||||
|
($this->success) ? 'success' : 'error',
|
||||||
|
$this->message
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->element(
|
||||||
|
'p',
|
||||||
|
'instructions',
|
||||||
|
// TRANS: Form instructions for group edit form.
|
||||||
|
_('Use this form to edit the group.')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showScripts()
|
||||||
|
{
|
||||||
|
parent::showScripts();
|
||||||
|
$this->autofocus('fullname');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare to run
|
* Prepare to run
|
||||||
|
* @param array $args
|
||||||
|
* @return bool
|
||||||
|
* @throws ClientException
|
||||||
|
* @throws NicknameException
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected function prepare(array $args=array())
|
protected function prepare(array $args = [])
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -74,7 +113,7 @@ class EditgroupAction extends GroupAction
|
|||||||
// Permanent redirect on non-canonical nickname
|
// Permanent redirect on non-canonical nickname
|
||||||
|
|
||||||
if ($nickname_arg != $nickname) {
|
if ($nickname_arg != $nickname) {
|
||||||
$args = array('nickname' => $nickname);
|
$args = ['nickname' => $nickname];
|
||||||
common_redirect(common_local_url('editgroup', $args), 301);
|
common_redirect(common_local_url('editgroup', $args), 301);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,85 +148,42 @@ class EditgroupAction extends GroupAction
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function handlePost()
|
||||||
* Handle the request
|
|
||||||
*
|
|
||||||
* On GET, show the form. On POST, try to save the group.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function handle()
|
|
||||||
{
|
{
|
||||||
parent::handle();
|
parent::handlePost();
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
||||||
$this->trySave();
|
|
||||||
} else {
|
|
||||||
$this->showForm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showForm($msg=null)
|
|
||||||
{
|
|
||||||
$this->msg = $msg;
|
|
||||||
$this->showPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showContent()
|
|
||||||
{
|
|
||||||
$form = new GroupEditForm($this, $this->group);
|
|
||||||
$form->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPageNotice()
|
|
||||||
{
|
|
||||||
if ($this->msg) {
|
|
||||||
$this->element('p', 'error', $this->msg);
|
|
||||||
} else {
|
|
||||||
$this->element('p', 'instructions',
|
|
||||||
// TRANS: Form instructions for group edit form.
|
|
||||||
_('Use this form to edit the group.'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showScripts()
|
|
||||||
{
|
|
||||||
parent::showScripts();
|
|
||||||
$this->autofocus('fullname');
|
|
||||||
}
|
|
||||||
|
|
||||||
function trySave()
|
|
||||||
{
|
|
||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
if (!$cur->isAdmin($this->group)) {
|
if (!$cur->isAdmin($this->group)) {
|
||||||
// TRANS: Client error displayed trying to edit a group while not being a group admin.
|
// TRANS: Client error displayed trying to edit a group while not being a group admin.
|
||||||
$this->clientError(_('You must be an admin to edit the group.'), 403);
|
$this->clientError(_('You must be an admin to edit the group.'), 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartGroupSaveForm', array($this))) {
|
if (Event::handle('StartGroupSaveForm', [$this])) {
|
||||||
|
|
||||||
// $nickname will only be set if this changenick value is true.
|
// $nickname will only be set if this changenick value is true.
|
||||||
|
$nickname = null;
|
||||||
if (common_config('profile', 'changenick') == true) {
|
if (common_config('profile', 'changenick') == true) {
|
||||||
try {
|
try {
|
||||||
$nickname = Nickname::normalize($this->trimmed('newnickname'), true);
|
$nickname = Nickname::normalize($this->trimmed('newnickname'), true);
|
||||||
} catch (NicknameTakenException $e) {
|
} catch (NicknameTakenException $e) {
|
||||||
// Abort only if the nickname is occupied by _another_ group
|
// Abort only if the nickname is occupied by _another_ group
|
||||||
if ($e->profile->id != $this->group->profile_id) {
|
if ($e->profile->id != $this->group->profile_id) {
|
||||||
$this->showForm($e->getMessage());
|
$this->setMessage($e->getMessage(), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$nickname = Nickname::normalize($this->trimmed('newnickname')); // without in-use check this time
|
$nickname = Nickname::normalize($this->trimmed('newnickname')); // without in-use check this time
|
||||||
} catch (NicknameException $e) {
|
} catch (NicknameException $e) {
|
||||||
$this->showForm($e->getMessage());
|
$this->setMessage($e->getMessage(), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$fullname = $this->trimmed('fullname');
|
$fullname = $this->trimmed('fullname');
|
||||||
$homepage = $this->trimmed('homepage');
|
$homepage = $this->trimmed('homepage');
|
||||||
$description = $this->trimmed('description');
|
$description = $this->trimmed('description');
|
||||||
$location = $this->trimmed('location');
|
$location = $this->trimmed('location');
|
||||||
$aliasstring = $this->trimmed('aliases');
|
$aliasstring = $this->trimmed('aliases');
|
||||||
$private = $this->boolean('private');
|
$private = $this->boolean('private');
|
||||||
|
|
||||||
if ($private) {
|
if ($private) {
|
||||||
$force_scope = 1;
|
$force_scope = 1;
|
||||||
@@ -198,42 +194,51 @@ class EditgroupAction extends GroupAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||||
!common_valid_http_url($homepage)) {
|
!common_valid_http_url($homepage)) {
|
||||||
// TRANS: Group edit form validation error.
|
// TRANS: Group edit form validation error.
|
||||||
$this->showForm(_('Homepage is not a valid URL.'));
|
$this->setMessage(_('Homepage is not a valid URL.'), true);
|
||||||
return;
|
return;
|
||||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
} elseif (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||||
// TRANS: Group edit form validation error.
|
// TRANS: Group edit form validation error.
|
||||||
$this->showForm(_('Full name is too long (maximum 255 characters).'));
|
$this->setMessage(_('Full name is too long (maximum 255 characters).'), true);
|
||||||
return;
|
return;
|
||||||
} else if (User_group::descriptionTooLong($description)) {
|
} elseif (User_group::descriptionTooLong($description)) {
|
||||||
$this->showForm(sprintf(
|
$this->setMessage(sprintf(
|
||||||
// TRANS: Group edit form validation error.
|
|
||||||
_m('Description is too long (maximum %d character).',
|
|
||||||
'Description is too long (maximum %d characters).',
|
|
||||||
User_group::maxDescription()),
|
|
||||||
User_group::maxDescription()));
|
|
||||||
return;
|
|
||||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
|
||||||
// TRANS: Group edit form validation error.
|
// TRANS: Group edit form validation error.
|
||||||
$this->showForm(_('Location is too long (maximum 255 characters).'));
|
_m(
|
||||||
|
'Description is too long (maximum %d character).',
|
||||||
|
'Description is too long (maximum %d characters).',
|
||||||
|
User_group::maxDescription()
|
||||||
|
),
|
||||||
|
User_group::maxDescription()
|
||||||
|
), true);
|
||||||
|
return;
|
||||||
|
} elseif (!is_null($location) && mb_strlen($location) > 255) {
|
||||||
|
// TRANS: Group edit form validation error.
|
||||||
|
$this->setMessage(_('Location is too long (maximum 255 characters).'), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($aliasstring)) {
|
if (!empty($aliasstring)) {
|
||||||
$aliases = array_map(array('Nickname', 'normalize'),
|
$aliases = array_map(
|
||||||
array_unique(preg_split('/[\s,]+/', $aliasstring)));
|
['Nickname', 'normalize'],
|
||||||
|
array_unique(preg_split('/[\s,]+/', $aliasstring))
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$aliases = array();
|
$aliases = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($aliases) > common_config('group', 'maxaliases')) {
|
if (count($aliases) > common_config('group', 'maxaliases')) {
|
||||||
// TRANS: Group edit form validation error.
|
// TRANS: Group edit form validation error.
|
||||||
// TRANS: %d is the maximum number of allowed aliases.
|
// TRANS: %d is the maximum number of allowed aliases.
|
||||||
$this->showForm(sprintf(_m('Too many aliases! Maximum %d allowed.',
|
$this->setMessage(sprintf(
|
||||||
'Too many aliases! Maximum %d allowed.',
|
_m(
|
||||||
common_config('group', 'maxaliases')),
|
'Too many aliases! Maximum %d allowed.',
|
||||||
common_config('group', 'maxaliases')));
|
'Too many aliases! Maximum %d allowed.',
|
||||||
|
common_config('group', 'maxaliases')
|
||||||
|
),
|
||||||
|
common_config('group', 'maxaliases')
|
||||||
|
), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,15 +247,15 @@ class EditgroupAction extends GroupAction
|
|||||||
$orig = clone($this->group);
|
$orig = clone($this->group);
|
||||||
|
|
||||||
if (common_config('profile', 'changenick') == true && $this->group->nickname !== $nickname) {
|
if (common_config('profile', 'changenick') == true && $this->group->nickname !== $nickname) {
|
||||||
assert(Nickname::normalize($nickname)===$nickname);
|
assert(Nickname::normalize($nickname) === $nickname);
|
||||||
common_debug("Changing group nickname from '{$profile->nickname}' to '{$nickname}'.");
|
common_debug("Changing group nickname from '{$this->group->nickname}' to '{$nickname}'.");
|
||||||
$this->group->nickname = $nickname;
|
$this->group->nickname = $nickname;
|
||||||
$this->group->mainpage = common_local_url('showgroup', array('nickname' => $this->group->nickname));
|
$this->group->mainpage = common_local_url('showgroup', ['nickname' => $this->group->nickname]);
|
||||||
}
|
}
|
||||||
$this->group->fullname = $fullname;
|
$this->group->fullname = $fullname;
|
||||||
$this->group->homepage = $homepage;
|
$this->group->homepage = $homepage;
|
||||||
$this->group->description = $description;
|
$this->group->description = $description;
|
||||||
$this->group->location = $location;
|
$this->group->location = $location;
|
||||||
$this->group->join_policy = $join_policy;
|
$this->group->join_policy = $join_policy;
|
||||||
$this->group->force_scope = $force_scope;
|
$this->group->force_scope = $force_scope;
|
||||||
|
|
||||||
@@ -271,14 +276,20 @@ class EditgroupAction extends GroupAction
|
|||||||
|
|
||||||
$this->group->query('COMMIT');
|
$this->group->query('COMMIT');
|
||||||
|
|
||||||
Event::handle('EndGroupSaveForm', array($this));
|
Event::handle('EndGroupSaveForm', [$this]);
|
||||||
|
|
||||||
|
if ($this->group->nickname != $orig->nickname) {
|
||||||
|
common_redirect(common_local_url('editgroup', ['nickname' => $this->group->nickname]), 303);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->group->nickname != $orig->nickname) {
|
// TRANS: Group edit form success message.
|
||||||
common_redirect(common_local_url('editgroup', array('nickname' => $this->group->nickname)), 303);
|
$this->setMessage(_('Options saved.'));
|
||||||
} else {
|
}
|
||||||
// TRANS: Group edit form success message.
|
|
||||||
$this->showForm(_('Options saved.'));
|
public function setMessage($msg, $error = false)
|
||||||
}
|
{
|
||||||
|
$this->message = $msg;
|
||||||
|
$this->success = !$error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -60,7 +60,7 @@ class EditpeopletagAction extends Action
|
|||||||
* Prepare to run
|
* Prepare to run
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -135,9 +135,9 @@ class EditpeopletagAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
$this->trySave();
|
$this->trySave();
|
||||||
} else {
|
} else {
|
||||||
|
@@ -369,8 +369,7 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
throw new ServerException(_('Could not insert confirmation code.'));
|
throw new ServerException(_('Could not insert confirmation code.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
common_debug('Sending confirmation address for user '.$user->getID().' to email '.$email);
|
$confirm->sendConfirmation();
|
||||||
mail_confirm_address($user, $confirm->code, $user->getNickname(), $email);
|
|
||||||
|
|
||||||
Event::handle('EndAddEmailAddress', array($user, $email));
|
Event::handle('EndAddEmailAddress', array($user, $email));
|
||||||
}
|
}
|
||||||
@@ -401,13 +400,7 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $confirm->delete();
|
$confirm->delete();
|
||||||
|
|
||||||
if ($result === false) {
|
|
||||||
common_log_db_error($confirm, 'DELETE', __FILE__);
|
|
||||||
// TRANS: Server error thrown on database error canceling e-mail address confirmation.
|
|
||||||
throw new ServerException(_('Could not delete email confirmation.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TRANS: Message given after successfully canceling e-mail address confirmation.
|
// TRANS: Message given after successfully canceling e-mail address confirmation.
|
||||||
return _('Email confirmation cancelled.');
|
return _('Email confirmation cancelled.');
|
||||||
|
@@ -54,7 +54,7 @@ class FeaturedAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
@@ -74,9 +74,9 @@ class FeaturedAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
@@ -35,7 +35,7 @@ class FoafGroupAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -76,9 +76,9 @@ class FoafGroupAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
header('Content-Type: application/rdf+xml');
|
header('Content-Type: application/rdf+xml');
|
||||||
|
|
||||||
|
@@ -47,7 +47,7 @@ class GeocodeAction extends Action
|
|||||||
var $lon = null;
|
var $lon = null;
|
||||||
var $location = null;
|
var $location = null;
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$token = $this->trimmed('token');
|
$token = $this->trimmed('token');
|
||||||
@@ -70,7 +70,7 @@ class GeocodeAction extends Action
|
|||||||
* @return nothing
|
* @return nothing
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
$location_object = array();
|
$location_object = array();
|
||||||
|
@@ -1,164 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* StatusNet - the distributed open-source microblogging tool
|
|
||||||
* Copyright (C) 2009, StatusNet, Inc.
|
|
||||||
*
|
|
||||||
* Return a requested file
|
|
||||||
*
|
|
||||||
* 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 PrivateAttachments
|
|
||||||
* @package StatusNet
|
|
||||||
* @author Jeffery To <jeffery.to@gmail.com>
|
|
||||||
* @copyright 2009 StatusNet, Inc.
|
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An action for returning a requested file
|
|
||||||
*
|
|
||||||
* The StatusNet system will do an implicit user check if the site is
|
|
||||||
* private before allowing this to continue
|
|
||||||
*
|
|
||||||
* @category PrivateAttachments
|
|
||||||
* @package StatusNet
|
|
||||||
* @author Jeffery To <jeffery.to@gmail.com>
|
|
||||||
* @copyright 2009 StatusNet, Inc.
|
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
|
||||||
class GetfileAction extends Action
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Path of file to return
|
|
||||||
*/
|
|
||||||
var $path = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get file name
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST array
|
|
||||||
*
|
|
||||||
* @return success flag
|
|
||||||
*/
|
|
||||||
protected function prepare(array $args=array())
|
|
||||||
{
|
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$filename = $this->trimmed('filename');
|
|
||||||
$path = null;
|
|
||||||
|
|
||||||
if ($filename && File::validFilename($filename)) {
|
|
||||||
$path = File::path($filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($path) or !file_exists($path)) {
|
|
||||||
// TRANS: Client error displayed when requesting a non-existent file.
|
|
||||||
$this->clientError(_('No such file.'), 404);
|
|
||||||
}
|
|
||||||
if (!is_readable($path)) {
|
|
||||||
// TRANS: Client error displayed when requesting a file without having read access to it.
|
|
||||||
$this->clientError(_('Cannot read file.'), 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->path = $path;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this page read-only?
|
|
||||||
*
|
|
||||||
* @return boolean true
|
|
||||||
*/
|
|
||||||
function isReadOnly($args)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Last-modified date for file
|
|
||||||
*
|
|
||||||
* @return int last-modified date as unix timestamp
|
|
||||||
*/
|
|
||||||
function lastModified()
|
|
||||||
{
|
|
||||||
if (common_config('site', 'use_x_sendfile')) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return filemtime($this->path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* etag for file
|
|
||||||
*
|
|
||||||
* This returns the same data (inode, size, mtime) as Apache would,
|
|
||||||
* but in decimal instead of hex.
|
|
||||||
*
|
|
||||||
* @return string etag http header
|
|
||||||
*/
|
|
||||||
function etag()
|
|
||||||
{
|
|
||||||
if (common_config('site', 'use_x_sendfile')) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = Cache::instance();
|
|
||||||
if($cache) {
|
|
||||||
$key = Cache::key('attachments:etag:' . $this->path);
|
|
||||||
$etag = $cache->get($key);
|
|
||||||
if($etag === false) {
|
|
||||||
$etag = crc32(file_get_contents($this->path));
|
|
||||||
$cache->set($key,$etag);
|
|
||||||
}
|
|
||||||
return $etag;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stat = stat($this->path);
|
|
||||||
return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle input, produce output
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function handle()
|
|
||||||
{
|
|
||||||
// undo headers set by PHP sessions
|
|
||||||
$sec = session_cache_expire() * 60;
|
|
||||||
header('Expires: ' . date(DATE_RFC1123, time() + $sec));
|
|
||||||
header('Cache-Control: max-age=' . $sec);
|
|
||||||
|
|
||||||
parent::handle();
|
|
||||||
|
|
||||||
$path = $this->path;
|
|
||||||
|
|
||||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
|
||||||
|
|
||||||
header('Content-Type: ' . $finfo->file($path));
|
|
||||||
|
|
||||||
if (common_config('site', 'use_x_sendfile')) {
|
|
||||||
header('X-Sendfile: ' . $path);
|
|
||||||
} else {
|
|
||||||
header('Content-Length: ' . filesize($path));
|
|
||||||
readfile($path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -49,7 +49,7 @@ class GrantRoleAction extends ProfileFormAction
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
if (!parent::prepare($args)) {
|
if (!parent::prepare($args)) {
|
||||||
return false;
|
return false;
|
||||||
|
@@ -52,7 +52,7 @@ class GroupblockAction extends RedirectingAction
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
@@ -110,9 +110,9 @@ class GroupblockAction extends RedirectingAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
if ($this->arg('no')) {
|
if ($this->arg('no')) {
|
||||||
$this->returnToPrevious();
|
$this->returnToPrevious();
|
||||||
|
@@ -42,7 +42,7 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
class GroupbyidAction extends ManagedAction
|
class GroupbyidAction extends ShowgroupAction
|
||||||
{
|
{
|
||||||
/** group we're viewing. */
|
/** group we're viewing. */
|
||||||
protected $group = null;
|
protected $group = null;
|
||||||
@@ -55,10 +55,10 @@ class GroupbyidAction extends ManagedAction
|
|||||||
protected function doPreparation()
|
protected function doPreparation()
|
||||||
{
|
{
|
||||||
$this->group = User_group::getByID($this->arg('id'));
|
$this->group = User_group::getByID($this->arg('id'));
|
||||||
}
|
$this->target = $this->group->getProfile();
|
||||||
|
|
||||||
public function showPage()
|
if ($this->target->isLocal()) {
|
||||||
{
|
common_redirect($this->target->getUrl());
|
||||||
common_redirect($this->group->homeUrl(), 303);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,9 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
if (!defined('GNUSOCIAL')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload an avatar
|
* Upload an avatar
|
||||||
@@ -40,21 +42,257 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @author Zach Copley <zach@status.net>
|
* @author Zach Copley <zach@status.net>
|
||||||
* @author Sarven Capadisli <csarven@status.net>
|
* @author Sarven Capadisli <csarven@status.net>
|
||||||
|
* @author Alexei Sorokin <sor.alexei@meowr.ru>
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
class GrouplogoAction extends GroupAction
|
class GrouplogoAction extends GroupAction
|
||||||
{
|
{
|
||||||
var $mode = null;
|
public $mode = null;
|
||||||
var $imagefile = null;
|
public $imagefile = null;
|
||||||
var $filename = null;
|
public $filename = null;
|
||||||
var $msg = null;
|
public $message = null;
|
||||||
var $success = null;
|
public $success = null;
|
||||||
|
protected $canPost = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the page
|
||||||
|
*
|
||||||
|
* @return string Title of the page
|
||||||
|
*/
|
||||||
|
public function title()
|
||||||
|
{
|
||||||
|
// TRANS: Title for group logo settings page.
|
||||||
|
return _('Group logo');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content area of the page
|
||||||
|
*
|
||||||
|
* Shows a form for uploading an avatar.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function showContent()
|
||||||
|
{
|
||||||
|
if ($this->mode == 'crop') {
|
||||||
|
$this->showCropForm();
|
||||||
|
} else {
|
||||||
|
$this->showUploadForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showCropForm()
|
||||||
|
{
|
||||||
|
$this->elementStart('form', array('method' => 'post',
|
||||||
|
'id' => 'form_settings_avatar',
|
||||||
|
'class' => 'form_settings',
|
||||||
|
'action' =>
|
||||||
|
common_local_url(
|
||||||
|
'grouplogo',
|
||||||
|
array('nickname' => $this->group->nickname)
|
||||||
|
)));
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
// TRANS: Legend for group logo settings fieldset.
|
||||||
|
$this->element('legend', null, _('Avatar settings'));
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
|
||||||
|
$this->elementStart(
|
||||||
|
'li',
|
||||||
|
array('id' => 'avatar_original',
|
||||||
|
'class' => 'avatar_view')
|
||||||
|
);
|
||||||
|
// TRANS: Header for originally uploaded file before a crop on the group logo page.
|
||||||
|
$this->element('h2', null, _('Original'));
|
||||||
|
$this->elementStart('div', array('id' => 'avatar_original_view'));
|
||||||
|
$this->element('img', array('src' => Avatar::url($this->filedata['filename']),
|
||||||
|
'width' => $this->filedata['width'],
|
||||||
|
'height' => $this->filedata['height'],
|
||||||
|
'alt' => $this->group->nickname));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
$this->elementEnd('li');
|
||||||
|
|
||||||
|
$this->elementStart(
|
||||||
|
'li',
|
||||||
|
array('id' => 'avatar_preview',
|
||||||
|
'class' => 'avatar_view')
|
||||||
|
);
|
||||||
|
// TRANS: Header for the cropped group logo on the group logo page.
|
||||||
|
$this->element('h2', null, _('Preview'));
|
||||||
|
$this->elementStart('div', array('id' => 'avatar_preview_view'));
|
||||||
|
$this->element('img', array('src' => Avatar::url($this->filedata['filename']),
|
||||||
|
'width' => AVATAR_PROFILE_SIZE,
|
||||||
|
'height' => AVATAR_PROFILE_SIZE,
|
||||||
|
'alt' => $this->group->nickname));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
|
||||||
|
foreach (array('avatar_crop_x', 'avatar_crop_y',
|
||||||
|
'avatar_crop_w', 'avatar_crop_h') as $crop_info) {
|
||||||
|
$this->element('input', array('name' => $crop_info,
|
||||||
|
'type' => 'hidden',
|
||||||
|
'id' => $crop_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TRANS: Button text for cropping an uploaded group logo.
|
||||||
|
$this->submit('crop', _('Crop'));
|
||||||
|
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showUploadForm()
|
||||||
|
{
|
||||||
|
$user = common_current_user();
|
||||||
|
|
||||||
|
$profile = $user->getProfile();
|
||||||
|
|
||||||
|
if (!$profile) {
|
||||||
|
common_log_db_error($user, 'SELECT', __FILE__);
|
||||||
|
// TRANS: Error message displayed when referring to a user without a profile.
|
||||||
|
$this->serverError(_('User has no profile.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$original = $this->group->original_logo;
|
||||||
|
|
||||||
|
$this->elementStart('form', array('enctype' => 'multipart/form-data',
|
||||||
|
'method' => 'post',
|
||||||
|
'id' => 'form_settings_avatar',
|
||||||
|
'class' => 'form_settings',
|
||||||
|
'action' =>
|
||||||
|
common_local_url(
|
||||||
|
'grouplogo',
|
||||||
|
array('nickname' => $this->group->nickname)
|
||||||
|
)));
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
// TRANS: Group logo form legend.
|
||||||
|
$this->element('legend', null, _('Group logo'));
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
if ($original) {
|
||||||
|
$this->elementStart('li', array('id' => 'avatar_original',
|
||||||
|
'class' => 'avatar_view'));
|
||||||
|
// TRANS: Uploaded original file in group logo form.
|
||||||
|
$this->element('h2', null, _('Original'));
|
||||||
|
$this->elementStart('div', array('id' => 'avatar_original_view'));
|
||||||
|
$this->element('img', array('src' => $this->group->original_logo,
|
||||||
|
'alt' => $this->group->nickname));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
$this->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->group->homepage_logo) {
|
||||||
|
$this->elementStart('li', array('id' => 'avatar_preview',
|
||||||
|
'class' => 'avatar_view'));
|
||||||
|
// TRANS: Header for preview of to be displayed group logo.
|
||||||
|
$this->element('h2', null, _('Preview'));
|
||||||
|
$this->elementStart('div', array('id' => 'avatar_preview_view'));
|
||||||
|
$this->element('img', array('src' => $this->group->homepage_logo,
|
||||||
|
'width' => AVATAR_PROFILE_SIZE,
|
||||||
|
'height' => AVATAR_PROFILE_SIZE,
|
||||||
|
'alt' => $this->group->nickname));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
if (!empty($this->group->homepage_logo)) {
|
||||||
|
// TRANS: Button on group logo upload page to delete current group logo.
|
||||||
|
$this->submit('delete', _('Delete'));
|
||||||
|
}
|
||||||
|
$this->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('li', array('id' => 'settings_attach'));
|
||||||
|
$this->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||||
|
'type' => 'hidden',
|
||||||
|
'id' => 'MAX_FILE_SIZE',
|
||||||
|
'value' => ImageFile::maxFileSizeInt()));
|
||||||
|
$this->element('input', array('name' => 'avatarfile',
|
||||||
|
'type' => 'file',
|
||||||
|
'id' => 'avatarfile'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
$this->elementStart('ul', 'form_actions');
|
||||||
|
$this->elementStart('li');
|
||||||
|
// TRANS: Submit button for uploading a group logo.
|
||||||
|
$this->submit('upload', _('Upload'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showPageNoticeBlock()
|
||||||
|
{
|
||||||
|
parent::showPageNoticeBlock();
|
||||||
|
|
||||||
|
if ($this->message) {
|
||||||
|
$this->element(
|
||||||
|
'div',
|
||||||
|
($this->success) ? 'success' : 'error',
|
||||||
|
$this->message
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$inst = $this->getInstructions();
|
||||||
|
$output = common_markup_to_html($inst);
|
||||||
|
|
||||||
|
$this->elementStart('div', 'instructions');
|
||||||
|
$this->raw($output);
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructions for use
|
||||||
|
*
|
||||||
|
* @return string instructions for use
|
||||||
|
*/
|
||||||
|
public function getInstructions()
|
||||||
|
{
|
||||||
|
// TRANS: Instructions for group logo page.
|
||||||
|
// TRANS: %s is the maximum file size for that site.
|
||||||
|
return sprintf(_('You can upload a logo image for your group. The maximum file size is %s.'), ImageFile::maxFileSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the jCrop stylesheet
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function showStylesheets()
|
||||||
|
{
|
||||||
|
parent::showStylesheets();
|
||||||
|
$this->cssLink('js/extlib/jquery-jcrop/css/jcrop.css', 'base', 'screen, projection, tv');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the jCrop scripts
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function showScripts()
|
||||||
|
{
|
||||||
|
parent::showScripts();
|
||||||
|
|
||||||
|
if ($this->mode == 'crop') {
|
||||||
|
$this->script('extlib/jquery-jcrop/jcrop.js');
|
||||||
|
$this->script('jcrop.go.js');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->autofocus('avatarfile');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare to run
|
* Prepare to run
|
||||||
|
* @param array $args
|
||||||
|
* @return bool
|
||||||
|
* @throws ClientException
|
||||||
|
* @throws NicknameException
|
||||||
*/
|
*/
|
||||||
protected function prepare(array $args=array())
|
protected function prepare(array $args = [])
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -104,220 +342,30 @@ class GrouplogoAction extends GroupAction
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handle()
|
|
||||||
{
|
|
||||||
parent::handle();
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
||||||
$this->handlePost();
|
|
||||||
} else {
|
|
||||||
$this->showForm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showForm($msg = null, $success = false)
|
|
||||||
{
|
|
||||||
$this->msg = $msg;
|
|
||||||
$this->success = $success;
|
|
||||||
|
|
||||||
$this->showPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Title of the page
|
|
||||||
*
|
|
||||||
* @return string Title of the page
|
|
||||||
*/
|
|
||||||
function title()
|
|
||||||
{
|
|
||||||
// TRANS: Title for group logo settings page.
|
|
||||||
return _('Group logo');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instructions for use
|
|
||||||
*
|
|
||||||
* @return instructions for use
|
|
||||||
*/
|
|
||||||
function getInstructions()
|
|
||||||
{
|
|
||||||
// TRANS: Instructions for group logo page.
|
|
||||||
// TRANS: %s is the maximum file size for that site.
|
|
||||||
return sprintf(_('You can upload a logo image for your group. The maximum file size is %s.'), ImageFile::maxFileSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Content area of the page
|
|
||||||
*
|
|
||||||
* Shows a form for uploading an avatar.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showContent()
|
|
||||||
{
|
|
||||||
if ($this->mode == 'crop') {
|
|
||||||
$this->showCropForm();
|
|
||||||
} else {
|
|
||||||
$this->showUploadForm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showUploadForm()
|
|
||||||
{
|
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$profile = $user->getProfile();
|
|
||||||
|
|
||||||
if (!$profile) {
|
|
||||||
common_log_db_error($user, 'SELECT', __FILE__);
|
|
||||||
// TRANS: Error message displayed when referring to a user without a profile.
|
|
||||||
$this->serverError(_('User has no profile.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$original = $this->group->original_logo;
|
|
||||||
|
|
||||||
$this->elementStart('form', array('enctype' => 'multipart/form-data',
|
|
||||||
'method' => 'post',
|
|
||||||
'id' => 'form_settings_avatar',
|
|
||||||
'class' => 'form_settings',
|
|
||||||
'action' =>
|
|
||||||
common_local_url('grouplogo',
|
|
||||||
array('nickname' => $this->group->nickname))));
|
|
||||||
$this->elementStart('fieldset');
|
|
||||||
// TRANS: Group logo form legend.
|
|
||||||
$this->element('legend', null, _('Group logo'));
|
|
||||||
$this->hidden('token', common_session_token());
|
|
||||||
|
|
||||||
$this->elementStart('ul', 'form_data');
|
|
||||||
if ($original) {
|
|
||||||
$this->elementStart('li', array('id' => 'avatar_original',
|
|
||||||
'class' => 'avatar_view'));
|
|
||||||
// TRANS: Uploaded original file in group logo form.
|
|
||||||
$this->element('h2', null, _('Original'));
|
|
||||||
$this->elementStart('div', array('id'=>'avatar_original_view'));
|
|
||||||
$this->element('img', array('src' => $this->group->original_logo,
|
|
||||||
'alt' => $this->group->nickname));
|
|
||||||
$this->elementEnd('div');
|
|
||||||
$this->elementEnd('li');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->group->homepage_logo) {
|
|
||||||
$this->elementStart('li', array('id' => 'avatar_preview',
|
|
||||||
'class' => 'avatar_view'));
|
|
||||||
// TRANS: Header for preview of to be displayed group logo.
|
|
||||||
$this->element('h2', null, _('Preview'));
|
|
||||||
$this->elementStart('div', array('id'=>'avatar_preview_view'));
|
|
||||||
$this->element('img', array('src' => $this->group->homepage_logo,
|
|
||||||
'width' => AVATAR_PROFILE_SIZE,
|
|
||||||
'height' => AVATAR_PROFILE_SIZE,
|
|
||||||
'alt' => $this->group->nickname));
|
|
||||||
$this->elementEnd('div');
|
|
||||||
$this->elementEnd('li');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementStart('li', array ('id' => 'settings_attach'));
|
|
||||||
$this->element('input', array('name' => 'MAX_FILE_SIZE',
|
|
||||||
'type' => 'hidden',
|
|
||||||
'id' => 'MAX_FILE_SIZE',
|
|
||||||
'value' => ImageFile::maxFileSizeInt()));
|
|
||||||
$this->element('input', array('name' => 'avatarfile',
|
|
||||||
'type' => 'file',
|
|
||||||
'id' => 'avatarfile'));
|
|
||||||
$this->elementEnd('li');
|
|
||||||
$this->elementEnd('ul');
|
|
||||||
|
|
||||||
$this->elementStart('ul', 'form_actions');
|
|
||||||
$this->elementStart('li');
|
|
||||||
// TRANS: Submit button for uploading a group logo.
|
|
||||||
$this->submit('upload', _('Upload'));
|
|
||||||
$this->elementEnd('li');
|
|
||||||
$this->elementEnd('ul');
|
|
||||||
|
|
||||||
$this->elementEnd('fieldset');
|
|
||||||
$this->elementEnd('form');
|
|
||||||
}
|
|
||||||
|
|
||||||
function showCropForm()
|
|
||||||
{
|
|
||||||
$this->elementStart('form', array('method' => 'post',
|
|
||||||
'id' => 'form_settings_avatar',
|
|
||||||
'class' => 'form_settings',
|
|
||||||
'action' =>
|
|
||||||
common_local_url('grouplogo',
|
|
||||||
array('nickname' => $this->group->nickname))));
|
|
||||||
$this->elementStart('fieldset');
|
|
||||||
// TRANS: Legend for group logo settings fieldset.
|
|
||||||
$this->element('legend', null, _('Avatar settings'));
|
|
||||||
$this->hidden('token', common_session_token());
|
|
||||||
|
|
||||||
$this->elementStart('ul', 'form_data');
|
|
||||||
|
|
||||||
$this->elementStart('li',
|
|
||||||
array('id' => 'avatar_original',
|
|
||||||
'class' => 'avatar_view'));
|
|
||||||
// TRANS: Header for originally uploaded file before a crop on the group logo page.
|
|
||||||
$this->element('h2', null, _('Original'));
|
|
||||||
$this->elementStart('div', array('id'=>'avatar_original_view'));
|
|
||||||
$this->element('img', array('src' => Avatar::url($this->filedata['filename']),
|
|
||||||
'width' => $this->filedata['width'],
|
|
||||||
'height' => $this->filedata['height'],
|
|
||||||
'alt' => $this->group->nickname));
|
|
||||||
$this->elementEnd('div');
|
|
||||||
$this->elementEnd('li');
|
|
||||||
|
|
||||||
$this->elementStart('li',
|
|
||||||
array('id' => 'avatar_preview',
|
|
||||||
'class' => 'avatar_view'));
|
|
||||||
// TRANS: Header for the cropped group logo on the group logo page.
|
|
||||||
$this->element('h2', null, _('Preview'));
|
|
||||||
$this->elementStart('div', array('id'=>'avatar_preview_view'));
|
|
||||||
$this->element('img', array('src' => Avatar::url($this->filedata['filename']),
|
|
||||||
'width' => AVATAR_PROFILE_SIZE,
|
|
||||||
'height' => AVATAR_PROFILE_SIZE,
|
|
||||||
'alt' => $this->group->nickname));
|
|
||||||
$this->elementEnd('div');
|
|
||||||
|
|
||||||
foreach (array('avatar_crop_x', 'avatar_crop_y',
|
|
||||||
'avatar_crop_w', 'avatar_crop_h') as $crop_info) {
|
|
||||||
$this->element('input', array('name' => $crop_info,
|
|
||||||
'type' => 'hidden',
|
|
||||||
'id' => $crop_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TRANS: Button text for cropping an uploaded group logo.
|
|
||||||
$this->submit('crop', _('Crop'));
|
|
||||||
|
|
||||||
$this->elementEnd('li');
|
|
||||||
$this->elementEnd('ul');
|
|
||||||
$this->elementEnd('fieldset');
|
|
||||||
$this->elementEnd('form');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a post
|
* Handle a post
|
||||||
*
|
*
|
||||||
* We mux on the button name to figure out what the user actually wanted.
|
* We mux on the button name to figure out what the user actually wanted.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
|
* @throws ClientException
|
||||||
|
* @throws NoResultException
|
||||||
|
* @throws UnsupportedMediaException
|
||||||
|
* @throws UseFileAsThumbnailException
|
||||||
*/
|
*/
|
||||||
function handlePost()
|
protected function handlePost()
|
||||||
{
|
{
|
||||||
// CSRF protection
|
parent::handlePost();
|
||||||
|
|
||||||
$token = $this->trimmed('token');
|
|
||||||
if (!$token || $token != common_session_token()) {
|
|
||||||
// TRANS: Form validation error message.
|
|
||||||
$this->show_form(_('There was a problem with your session token. '.
|
|
||||||
'Try again, please.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->arg('upload')) {
|
if ($this->arg('upload')) {
|
||||||
$this->uploadLogo();
|
$this->uploadLogo();
|
||||||
} else if ($this->arg('crop')) {
|
} elseif ($this->arg('crop')) {
|
||||||
$this->cropLogo();
|
$this->cropLogo();
|
||||||
|
} elseif ($this->arg('delete')) {
|
||||||
|
$this->deleteLogo();
|
||||||
} else {
|
} else {
|
||||||
// TRANS: Form validation error message when an unsupported argument is used.
|
// TRANS: Form validation error message when an unsupported argument is used.
|
||||||
$this->showForm(_('Unexpected form submission.'));
|
$this->setMessage(_('Unexpected form submission.'), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,30 +377,32 @@ class GrouplogoAction extends GroupAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function uploadLogo()
|
public function uploadLogo()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$imagefile = ImageFile::fromUpload('avatarfile');
|
$imagefile = ImageFile::fromUpload('avatarfile');
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->showForm($e->getMessage());
|
$this->setMessage($e->getMessage(), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = $imagefile->preferredType();
|
$type = $imagefile->preferredType();
|
||||||
$filename = Avatar::filename($this->group->id,
|
$filename = Avatar::filename(
|
||||||
image_type_to_extension($type),
|
$this->group->id,
|
||||||
null,
|
image_type_to_extension($type),
|
||||||
'group-temp-'.common_timestamp());
|
null,
|
||||||
|
'group-temp-' . common_timestamp()
|
||||||
|
);
|
||||||
|
|
||||||
$filepath = Avatar::path($filename);
|
$filepath = Avatar::path($filename);
|
||||||
|
|
||||||
$imagefile->copyTo($filepath);
|
$imagefile->copyTo($filepath);
|
||||||
|
|
||||||
$filedata = array('filename' => $filename,
|
$filedata = array('filename' => $filename,
|
||||||
'filepath' => $filepath,
|
'filepath' => $filepath,
|
||||||
'width' => $imagefile->width,
|
'width' => $imagefile->width,
|
||||||
'height' => $imagefile->height,
|
'height' => $imagefile->height,
|
||||||
'type' => $type);
|
'type' => $type);
|
||||||
|
|
||||||
$_SESSION['FILEDATA'] = $filedata;
|
$_SESSION['FILEDATA'] = $filedata;
|
||||||
|
|
||||||
@@ -361,16 +411,24 @@ class GrouplogoAction extends GroupAction
|
|||||||
$this->mode = 'crop';
|
$this->mode = 'crop';
|
||||||
|
|
||||||
// TRANS: Form instructions on the group logo page.
|
// TRANS: Form instructions on the group logo page.
|
||||||
$this->showForm(_('Pick a square area of the image to be the logo.'),
|
$this->setMessage(_('Pick a square area of the image to be the logo.'));
|
||||||
true);
|
}
|
||||||
|
|
||||||
|
public function setMessage($msg, $error = false)
|
||||||
|
{
|
||||||
|
$this->message = $msg;
|
||||||
|
$this->success = !$error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the results of jcrop.
|
* Handle the results of jcrop.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
|
* @throws NoResultException
|
||||||
|
* @throws UnsupportedMediaException
|
||||||
|
* @throws UseFileAsThumbnailException
|
||||||
*/
|
*/
|
||||||
function cropLogo()
|
public function cropLogo()
|
||||||
{
|
{
|
||||||
$filedata = $_SESSION['FILEDATA'];
|
$filedata = $_SESSION['FILEDATA'];
|
||||||
|
|
||||||
@@ -380,20 +438,24 @@ class GrouplogoAction extends GroupAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If image is not being cropped assume pos & dimentions of original
|
// If image is not being cropped assume pos & dimentions of original
|
||||||
$dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0;
|
$dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x') : 0;
|
||||||
$dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0;
|
$dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y') : 0;
|
||||||
$dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$filedata['width'];
|
$dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w') : $filedata['width'];
|
||||||
$dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$filedata['height'];
|
$dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h') : $filedata['height'];
|
||||||
$size = min($dest_w, $dest_h, common_config('avatar', 'maxsize'));
|
$size = min($dest_w, $dest_h, common_config('avatar', 'maxsize'));
|
||||||
$box = array('width' => $size, 'height' => $size,
|
$box = array('width' => $size, 'height' => $size,
|
||||||
'x' => $dest_x, 'y' => $dest_y,
|
'x' => $dest_x, 'y' => $dest_y,
|
||||||
'w' => $dest_w, 'h' => $dest_h);
|
'w' => $dest_w, 'h' => $dest_h);
|
||||||
|
|
||||||
$profile = $this->group->getProfile();
|
$profile = $this->group->getProfile();
|
||||||
|
|
||||||
$imagefile = new ImageFile(null, $filedata['filepath']);
|
$imagefile = new ImageFile(null, $filedata['filepath']);
|
||||||
$filename = Avatar::filename($profile->getID(), image_type_to_extension($imagefile->preferredType()),
|
$filename = Avatar::filename(
|
||||||
$size, common_timestamp());
|
$profile->getID(),
|
||||||
|
image_type_to_extension($imagefile->preferredType()),
|
||||||
|
$size,
|
||||||
|
common_timestamp()
|
||||||
|
);
|
||||||
|
|
||||||
$imagefile->resizeTo(Avatar::path($filename), $box);
|
$imagefile->resizeTo(Avatar::path($filename), $box);
|
||||||
|
|
||||||
@@ -402,53 +464,33 @@ class GrouplogoAction extends GroupAction
|
|||||||
unset($_SESSION['FILEDATA']);
|
unset($_SESSION['FILEDATA']);
|
||||||
$this->mode = 'upload';
|
$this->mode = 'upload';
|
||||||
// TRANS: Form success message after updating a group logo.
|
// TRANS: Form success message after updating a group logo.
|
||||||
$this->showForm(_('Logo updated.'), true);
|
$this->setMessage(_('Logo updated.'));
|
||||||
} else {
|
} else {
|
||||||
// TRANS: Form failure message after failing to update a group logo.
|
// TRANS: Form failure message after failing to update a group logo.
|
||||||
$this->showForm(_('Failed updating logo.'));
|
$this->setMessage(_('Failed updating logo.'), true);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPageNotice()
|
|
||||||
{
|
|
||||||
if ($this->msg) {
|
|
||||||
$this->element('div', ($this->success) ? 'success' : 'error',
|
|
||||||
$this->msg);
|
|
||||||
} else {
|
|
||||||
$inst = $this->getInstructions();
|
|
||||||
$output = common_markup_to_html($inst);
|
|
||||||
|
|
||||||
$this->elementStart('div', 'instructions');
|
|
||||||
$this->raw($output);
|
|
||||||
$this->elementEnd('div');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the jCrop stylesheet
|
* Get rid of the current group logo.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function showStylesheets()
|
public function deleteLogo()
|
||||||
{
|
{
|
||||||
parent::showStylesheets();
|
$orig = clone($this->group);
|
||||||
$this->cssLink('js/extlib/jquery-jcrop/css/jcrop.css','base','screen, projection, tv');
|
Avatar::deleteFromProfile($this->group->getProfile());
|
||||||
}
|
@unlink(Avatar::path(basename($this->group->original_logo)));
|
||||||
|
@unlink(Avatar::path(basename($this->group->homepage_logo)));
|
||||||
|
@unlink(Avatar::path(basename($this->group->stream_logo)));
|
||||||
|
@unlink(Avatar::path(basename($this->group->mini_logo)));
|
||||||
|
$this->group->original_logo = User_group::defaultLogo(AVATAR_PROFILE_SIZE);
|
||||||
|
$this->group->homepage_logo = User_group::defaultLogo(AVATAR_PROFILE_SIZE);
|
||||||
|
$this->group->stream_logo = User_group::defaultLogo(AVATAR_STREAM_SIZE);
|
||||||
|
$this->group->mini_logo = User_group::defaultLogo(AVATAR_MINI_SIZE);
|
||||||
|
$this->group->update($orig);
|
||||||
|
|
||||||
/**
|
// TRANS: Success message for deleting the group logo.
|
||||||
* Add the jCrop scripts
|
$this->setMessage(_('Logo deleted.'));
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showScripts()
|
|
||||||
{
|
|
||||||
parent::showScripts();
|
|
||||||
|
|
||||||
if ($this->mode == 'crop') {
|
|
||||||
$this->script('extlib/jquery-jcrop/jcrop.js');
|
|
||||||
$this->script('jcrop.go.js');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->autofocus('avatarfile');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,12 +27,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/profilelist.php');
|
|
||||||
require_once INSTALLDIR.'/lib/publicgroupnav.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of group members
|
* List of group members
|
||||||
@@ -52,15 +47,6 @@ class GroupmembersAction extends GroupAction
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function prepare(array $args=array())
|
|
||||||
{
|
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
|
@@ -153,7 +153,7 @@ class GroupqueueAction extends GroupAction
|
|||||||
// @todo FIXME: documentation missing.
|
// @todo FIXME: documentation missing.
|
||||||
class GroupQueueList extends GroupMemberList
|
class GroupQueueList extends GroupMemberList
|
||||||
{
|
{
|
||||||
function newListItem($profile)
|
function newListItem(Profile $profile)
|
||||||
{
|
{
|
||||||
return new GroupQueueListItem($profile, $this->group, $this->action);
|
return new GroupQueueListItem($profile, $this->group, $this->action);
|
||||||
}
|
}
|
||||||
|
@@ -67,16 +67,16 @@ class GroupsAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ class GroupunblockAction extends Action
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
@@ -103,9 +103,9 @@ class GroupunblockAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
$this->unblockProfile();
|
$this->unblockProfile();
|
||||||
}
|
}
|
||||||
|
@@ -359,13 +359,7 @@ class ImsettingsAction extends SettingsAction
|
|||||||
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $confirm->delete();
|
$confirm->delete();
|
||||||
|
|
||||||
if ($result === false) {
|
|
||||||
common_log_db_error($confirm, 'DELETE', __FILE__);
|
|
||||||
// TRANS: Server error thrown on database error canceling IM address confirmation.
|
|
||||||
throw new ServerException(_('Could not delete confirmation.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TRANS: Message given after successfully canceling IM address confirmation.
|
// TRANS: Message given after successfully canceling IM address confirmation.
|
||||||
return _('IM confirmation cancelled.');
|
return _('IM confirmation cancelled.');
|
||||||
|
@@ -38,9 +38,9 @@ class InviteAction extends Action
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
if (!common_config('invite', 'enabled')) {
|
if (!common_config('invite', 'enabled')) {
|
||||||
// TRANS: Client error displayed when trying to sent invites while they have been disabled.
|
// TRANS: Client error displayed when trying to sent invites while they have been disabled.
|
||||||
$this->clientError(_('Invites have been disabled.'));
|
$this->clientError(_('Invites have been disabled.'));
|
||||||
|
@@ -54,7 +54,7 @@ class MakeadminAction extends RedirectingAction
|
|||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
@@ -111,9 +111,9 @@ class MakeadminAction extends RedirectingAction
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
$this->makeAdmin();
|
$this->makeAdmin();
|
||||||
}
|
}
|
||||||
|
@@ -1,82 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Microsummary action, see https://wiki.mozilla.org/Microsummaries
|
|
||||||
*
|
|
||||||
* 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('STATUSNET') && !defined('LACONICA')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Microsummary action class.
|
|
||||||
*
|
|
||||||
* @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 MicrosummaryAction extends Action
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Class handler.
|
|
||||||
*
|
|
||||||
* @param array $args array of arguments
|
|
||||||
*
|
|
||||||
* @return nothing
|
|
||||||
*/
|
|
||||||
function handle($args)
|
|
||||||
{
|
|
||||||
parent::handle($args);
|
|
||||||
|
|
||||||
$nickname = common_canonical_nickname($this->arg('nickname'));
|
|
||||||
$user = User::getKV('nickname', $nickname);
|
|
||||||
|
|
||||||
if (!$user) {
|
|
||||||
// TRANS: Client error displayed trying to make a micro summary without providing a valid user.
|
|
||||||
$this->clientError(_('No such user.'), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$notice = $user->getCurrentNotice();
|
|
||||||
|
|
||||||
if (!$notice) {
|
|
||||||
// TRANS: Client error displayed trying to make a micro summary without providing a status.
|
|
||||||
$this->clientError(_('No current status.'), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Content-Type: text/plain');
|
|
||||||
|
|
||||||
print $user->nickname . ': ' . $notice->content;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isReadOnly($args)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -49,25 +49,36 @@ class NetworkpublicAction extends SitestreamAction
|
|||||||
// Network public tag cloud?
|
// Network public tag cloud?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output <head> elements for RSS and Atom feeds
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
function getFeeds()
|
function getFeeds()
|
||||||
{
|
{
|
||||||
return array(new Feed(Feed::JSON,
|
return [
|
||||||
common_local_url('ApiTimelineNetworkPublic',
|
new Feed(Feed::ATOM,
|
||||||
array('format' => 'as')),
|
common_local_url('ApiTimelinePublic',
|
||||||
// TRANS: Link description for the _global_ network public timeline feed.
|
array('format' => 'atom')),
|
||||||
_('Network Public Timeline Feed (Activity Streams JSON)')),
|
// TRANS: Link description for public timeline feed.
|
||||||
new Feed(Feed::RSS1, common_local_url('publicrss'),
|
_('Public Timeline Feed (Atom)')
|
||||||
// TRANS: Link description for the _global_ network public timeline feed.
|
),
|
||||||
_('Network Public Timeline Feed (RSS 1.0)')),
|
new Feed(Feed::JSON,
|
||||||
new Feed(Feed::RSS2,
|
common_local_url('ApiTimelinePublic',
|
||||||
common_local_url('ApiTimelineNetworkPublic',
|
array('format' => 'as')),
|
||||||
array('format' => 'rss')),
|
// TRANS: Link description for public timeline feed.
|
||||||
// TRANS: Link description for the _global_ network public timeline feed.
|
_('Public Timeline Feed (Activity Streams JSON)')
|
||||||
_('Network Public Timeline Feed (RSS 2.0)')),
|
),
|
||||||
new Feed(Feed::ATOM,
|
new Feed(Feed::RSS1, common_local_url('publicrss'),
|
||||||
common_local_url('ApiTimelineNetworkPublic',
|
// TRANS: Link description for public timeline feed.
|
||||||
array('format' => 'atom')),
|
_('Public Timeline Feed (RSS 1.0)')
|
||||||
// TRANS: Link description for the _global_ network public timeline feed.
|
),
|
||||||
_('Network Public Timeline Feed (Atom)')));
|
new Feed(Feed::RSS2,
|
||||||
|
common_local_url('ApiTimelinePublic',
|
||||||
|
array('format' => 'rss')),
|
||||||
|
// TRANS: Link description for public timeline feed.
|
||||||
|
_('Public Timeline Feed (RSS 2.0)')
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -47,6 +47,8 @@ class NewnoticeAction extends FormAction
|
|||||||
{
|
{
|
||||||
protected $form = 'Notice';
|
protected $form = 'Notice';
|
||||||
|
|
||||||
|
protected $inreplyto = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title of the page
|
* Title of the page
|
||||||
*
|
*
|
||||||
@@ -75,6 +77,11 @@ class NewnoticeAction extends FormAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->int('inreplyto')) {
|
||||||
|
// Throws exception if the inreplyto Notice is given but not found.
|
||||||
|
$this->inreplyto = Notice::getByID($this->int('inreplyto'));
|
||||||
|
}
|
||||||
|
|
||||||
// Backwards compatibility for "share this" widget things.
|
// Backwards compatibility for "share this" widget things.
|
||||||
// If no 'content', use 'status_textarea'
|
// If no 'content', use 'status_textarea'
|
||||||
$this->formOpts['content'] = $this->trimmed('content') ?: $this->trimmed('status_textarea');
|
$this->formOpts['content'] = $this->trimmed('content') ?: $this->trimmed('status_textarea');
|
||||||
@@ -115,7 +122,7 @@ class NewnoticeAction extends FormAction
|
|||||||
// simply no attached media to the new notice
|
// simply no attached media to the new notice
|
||||||
if (empty($content)) {
|
if (empty($content)) {
|
||||||
// TRANS: Client error displayed trying to send a notice without content.
|
// TRANS: Client error displayed trying to send a notice without content.
|
||||||
$this->clientError(_('No content!'));
|
throw new ClientException(_('No content!'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,13 +139,6 @@ class NewnoticeAction extends FormAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->int('inreplyto')) {
|
|
||||||
// Throws exception if the inreplyto Notice is given but not found.
|
|
||||||
$parent = Notice::getByID($this->int('inreplyto'));
|
|
||||||
} else {
|
|
||||||
$parent = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$act = new Activity();
|
$act = new Activity();
|
||||||
$act->verb = ActivityVerb::POST;
|
$act->verb = ActivityVerb::POST;
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
@@ -157,9 +157,9 @@ class NewnoticeAction extends FormAction
|
|||||||
|
|
||||||
$act->context = new ActivityContext();
|
$act->context = new ActivityContext();
|
||||||
|
|
||||||
if ($parent instanceof Notice) {
|
if ($this->inreplyto instanceof Notice) {
|
||||||
$act->context->replyToID = $parent->getUri();
|
$act->context->replyToID = $this->inreplyto->getUri();
|
||||||
$act->context->replyToUrl = $parent->getUrl(true); // maybe we don't have to send true here to force a URL?
|
$act->context->replyToUrl = $this->inreplyto->getUrl(true); // maybe we don't have to send true here to force a URL?
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->scoped->shareLocation()) {
|
if ($this->scoped->shareLocation()) {
|
||||||
@@ -188,14 +188,14 @@ class NewnoticeAction extends FormAction
|
|||||||
|
|
||||||
// FIXME: We should be able to get the attentions from common_render_content!
|
// FIXME: We should be able to get the attentions from common_render_content!
|
||||||
// and maybe even directly save whether they're local or not!
|
// and maybe even directly save whether they're local or not!
|
||||||
$act->context->attention = common_get_attentions($content, $this->scoped, $parent);
|
$act->context->attention = common_get_attentions($content, $this->scoped, $this->inreplyto);
|
||||||
|
|
||||||
// $options gets filled with possible scoping settings
|
// $options gets filled with possible scoping settings
|
||||||
ToSelector::fillActivity($this, $act, $options);
|
ToSelector::fillActivity($this, $act, $options);
|
||||||
|
|
||||||
$actobj = new ActivityObject();
|
$actobj = new ActivityObject();
|
||||||
$actobj->type = ActivityObject::NOTE;
|
$actobj->type = ActivityObject::NOTE;
|
||||||
$actobj->content = common_render_content($content, $this->scoped, $parent);
|
$actobj->content = common_render_content($content, $this->scoped, $this->inreplyto);
|
||||||
|
|
||||||
// Finally add the activity object to our activity
|
// Finally add the activity object to our activity
|
||||||
$act->objects[] = $actobj;
|
$act->objects[] = $actobj;
|
||||||
@@ -224,6 +224,9 @@ class NewnoticeAction extends FormAction
|
|||||||
if ($this->getInfo() && $this->stored instanceof Notice) {
|
if ($this->getInfo() && $this->stored instanceof Notice) {
|
||||||
$this->showNotice($this->stored);
|
$this->showNotice($this->stored);
|
||||||
} elseif (!$this->getError()) {
|
} elseif (!$this->getError()) {
|
||||||
|
if (!GNUsocial::isAjax() && $this->inreplyto instanceof Notice) {
|
||||||
|
$this->showNotice($this->inreplyto);
|
||||||
|
}
|
||||||
parent::showContent();
|
parent::showContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,14 +50,14 @@ class NoticesearchAction extends SearchAction
|
|||||||
{
|
{
|
||||||
protected $q = null;
|
protected $q = null;
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
$this->q = $this->trimmed('q');
|
$this->q = $this->trimmed('q');
|
||||||
|
|
||||||
// FIXME: very dependent on tag format
|
// FIXME: very dependent on tag format
|
||||||
if (preg_match('/^#([\pL\pN_\-\.]{1,64})/ue', $this->q)) {
|
if (preg_match('/^\#([\pL\pN_\-\.]{1,64})/u', $this->q)) {
|
||||||
common_redirect(common_local_url('tag',
|
common_redirect(common_local_url('tag',
|
||||||
array('tag' => common_canonical_tag(substr($this->q, 1)))),
|
array('tag' => common_canonical_tag(substr($this->q, 1)))),
|
||||||
303);
|
303);
|
||||||
@@ -65,8 +65,7 @@ class NoticesearchAction extends SearchAction
|
|||||||
|
|
||||||
if (!empty($this->q)) {
|
if (!empty($this->q)) {
|
||||||
|
|
||||||
$profile = Profile::current();
|
$stream = new SearchNoticeStream($this->q, $this->scoped);
|
||||||
$stream = new SearchNoticeStream($this->q, $profile);
|
|
||||||
$page = $this->trimmed('page');
|
$page = $this->trimmed('page');
|
||||||
|
|
||||||
if (empty($page)) {
|
if (empty($page)) {
|
||||||
@@ -186,7 +185,7 @@ class SearchNoticeList extends NoticeList {
|
|||||||
$this->terms = $terms;
|
$this->terms = $terms;
|
||||||
}
|
}
|
||||||
|
|
||||||
function newListItem($notice)
|
function newListItem(Notice $notice)
|
||||||
{
|
{
|
||||||
return new SearchNoticeListItem($notice, $this->out, $this->terms);
|
return new SearchNoticeListItem($notice, $this->out, $this->terms);
|
||||||
}
|
}
|
||||||
|
@@ -55,9 +55,9 @@ class NudgeAction extends Action
|
|||||||
*
|
*
|
||||||
* @return nothing
|
* @return nothing
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
// TRANS: Error message displayed when trying to perform an action that requires a logged in user.
|
// TRANS: Error message displayed when trying to perform an action that requires a logged in user.
|
||||||
|
@@ -53,9 +53,9 @@ class OpensearchAction extends Action
|
|||||||
*
|
*
|
||||||
* @return boolean false if user doesn't exist
|
* @return boolean false if user doesn't exist
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$type = $this->trimmed('type');
|
$type = $this->trimmed('type');
|
||||||
$short_name = '';
|
$short_name = '';
|
||||||
if ($type == 'people') {
|
if ($type == 'people') {
|
||||||
|
@@ -53,7 +53,7 @@ class OtpAction extends Action
|
|||||||
var $returnto;
|
var $returnto;
|
||||||
var $lt;
|
var $lt;
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -110,9 +110,9 @@ class OtpAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
// success!
|
// success!
|
||||||
if (!common_set_user($this->user)) {
|
if (!common_set_user($this->user)) {
|
||||||
|
@@ -28,7 +28,9 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) { exit(1); }
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change password
|
* Change password
|
||||||
@@ -40,7 +42,6 @@ if (!defined('STATUSNET')) { exit(1); }
|
|||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PasswordsettingsAction extends SettingsAction
|
class PasswordsettingsAction extends SettingsAction
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -49,37 +50,36 @@ class PasswordsettingsAction extends SettingsAction
|
|||||||
* @return string Title of the page
|
* @return string Title of the page
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function title()
|
public function title()
|
||||||
{
|
{
|
||||||
// TRANS: Title for page where to change password.
|
// TRANS: Title for page where to change password.
|
||||||
return _m('TITLE','Change password');
|
return _m('TITLE', 'Change password');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instructions for use
|
* Instructions for use
|
||||||
*
|
*
|
||||||
* @return instructions for use
|
* @return string instructions for use
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function getInstructions()
|
public function getInstructions()
|
||||||
{
|
{
|
||||||
// TRANS: Instructions for page where to change password.
|
// TRANS: Instructions for page where to change password.
|
||||||
return _('Change your password.');
|
return _('Change your password.');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showScripts()
|
public function showScripts()
|
||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
$this->autofocus('oldpassword');
|
$this->autofocus('oldpassword');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showContent()
|
public function showContent()
|
||||||
{
|
{
|
||||||
$this->elementStart('form', array('method' => 'POST',
|
$this->elementStart('form', ['method' => 'POST',
|
||||||
'id' => 'form_password',
|
'id' => 'form_password',
|
||||||
'class' => 'form_settings',
|
'class' => 'form_settings',
|
||||||
'action' =>
|
'action' => common_local_url('passwordsettings')]);
|
||||||
common_local_url('passwordsettings')));
|
|
||||||
$this->elementStart('fieldset');
|
$this->elementStart('fieldset');
|
||||||
// TRANS: Fieldset legend on page where to change password.
|
// TRANS: Fieldset legend on page where to change password.
|
||||||
$this->element('legend', null, _('Password change'));
|
$this->element('legend', null, _('Password change'));
|
||||||
@@ -102,14 +102,14 @@ class PasswordsettingsAction extends SettingsAction
|
|||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
// TRANS: Field label on page where to change password. In this field the new password should be typed a second time.
|
// TRANS: Field label on page where to change password. In this field the new password should be typed a second time.
|
||||||
$this->password('confirm', _m('LABEL','Confirm'),
|
$this->password('confirm', _m('LABEL', 'Confirm'),
|
||||||
// TRANS: Field title on page where to change password.
|
// TRANS: Field title on page where to change password.
|
||||||
_('Same as password above.'));
|
_('Same as password above.'));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
// TRANS: Button text on page where to change password.
|
// TRANS: Button text on page where to change password.
|
||||||
$this->submit('changepass', _m('BUTTON','Change'));
|
$this->submit('changepass', _m('BUTTON', 'Change'));
|
||||||
|
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
@@ -120,14 +120,14 @@ class PasswordsettingsAction extends SettingsAction
|
|||||||
// FIXME: scrub input
|
// FIXME: scrub input
|
||||||
|
|
||||||
$newpassword = $this->arg('newpassword');
|
$newpassword = $this->arg('newpassword');
|
||||||
$confirm = $this->arg('confirm');
|
$confirm = $this->arg('confirm');
|
||||||
|
|
||||||
// Some validation
|
// Some validation
|
||||||
|
|
||||||
if (strlen($newpassword) < 6) {
|
if (strlen($newpassword) < 6) {
|
||||||
// TRANS: Form validation error on page where to change password.
|
// TRANS: Form validation error on page where to change password.
|
||||||
throw new ClientException(_('Password must be 6 or more characters.'));
|
throw new ClientException(_('Password must be 6 or more characters.'));
|
||||||
} else if (0 != strcmp($newpassword, $confirm)) {
|
} elseif (0 != strcmp($newpassword, $confirm)) {
|
||||||
// TRANS: Form validation error on password change when password confirmation does not match.
|
// TRANS: Form validation error on password change when password confirmation does not match.
|
||||||
throw new ClientException(_('Passwords do not match.'));
|
throw new ClientException(_('Passwords do not match.'));
|
||||||
}
|
}
|
||||||
@@ -142,11 +142,12 @@ class PasswordsettingsAction extends SettingsAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartChangePassword', array($this->scoped, $oldpassword, $newpassword))) {
|
if (Event::handle('StartChangePassword', [$this->scoped, $oldpassword, $newpassword])) {
|
||||||
//no handler changed the password, so change the password internally
|
// no handler changed the password, so change the password internally
|
||||||
|
$user = $this->scoped->getUser();
|
||||||
$user->setPassword($newpassword);
|
$user->setPassword($newpassword);
|
||||||
|
|
||||||
Event::handle('EndChangePassword', array($this->scoped));
|
Event::handle('EndChangePassword', [$this->scoped]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TRANS: Form validation notice on page where to change password.
|
// TRANS: Form validation notice on page where to change password.
|
||||||
|
@@ -62,7 +62,7 @@ class PeopletagAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
@@ -84,9 +84,9 @@ class PeopletagAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ class PeopletagautocompleteAction extends Action
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ class PeopletagautocompleteAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
//common_log(LOG_DEBUG, 'Autocomplete data: ' . json_encode($this->tags));
|
//common_log(LOG_DEBUG, 'Autocomplete data: ' . json_encode($this->tags));
|
||||||
if ($this->tags) {
|
if ($this->tags) {
|
||||||
|
@@ -53,7 +53,7 @@ class PeopletaggedAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
@@ -117,9 +117,9 @@ class PeopletaggedAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ class PeopletagMemberList extends ProfileList
|
|||||||
$this->peopletag = $peopletag;
|
$this->peopletag = $peopletag;
|
||||||
}
|
}
|
||||||
|
|
||||||
function newListItem($profile)
|
function newListItem(Profile $profile)
|
||||||
{
|
{
|
||||||
return new PeopletagMemberListItem($profile, $this->peopletag, $this->action);
|
return new PeopletagMemberListItem($profile, $this->peopletag, $this->action);
|
||||||
}
|
}
|
||||||
|
@@ -68,7 +68,7 @@ class PeopletagsbyuserAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -135,9 +135,9 @@ class PeopletagsbyuserAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
# Post from the tag dropdown; redirect to a GET
|
# Post from the tag dropdown; redirect to a GET
|
||||||
|
|
||||||
|
@@ -54,7 +54,7 @@ class PeopletagsforuserAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -95,9 +95,9 @@ class PeopletagsforuserAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,7 +53,7 @@ class PeopletagsubscribersAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
@@ -117,9 +117,9 @@ class PeopletagsubscribersAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ class PeopletagSubscriberList extends ProfileList
|
|||||||
$this->peopletag = $peopletag;
|
$this->peopletag = $peopletag;
|
||||||
}
|
}
|
||||||
|
|
||||||
function newListItem($profile)
|
function newListItem(Profile $profile)
|
||||||
{
|
{
|
||||||
return new PeopletagSubscriberListItem($profile, $this->peopletag, $this->action);
|
return new PeopletagSubscriberListItem($profile, $this->peopletag, $this->action);
|
||||||
}
|
}
|
||||||
|
@@ -56,7 +56,7 @@ class PeopletagsubscriptionsAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -97,9 +97,9 @@ class PeopletagsubscriptionsAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -64,7 +64,7 @@ class PluginEnableAction extends Action
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ class PluginEnableAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
$key = 'disable-' . $this->plugin;
|
$key = 'disable-' . $this->plugin;
|
||||||
Config::save('plugins', $key, $this->overrideValue());
|
Config::save('plugins', $key, $this->overrideValue());
|
||||||
|
@@ -68,7 +68,7 @@ class ProfilecompletionAction extends Action
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ class ProfilecompletionAction extends Action
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
$this->msg = null;
|
$this->msg = null;
|
||||||
|
|
||||||
|
@@ -45,7 +45,7 @@ class ProfiletagbyidAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
function prepare(array $args = array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ class ProfiletagbyidAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
function handle()
|
||||||
{
|
{
|
||||||
common_redirect($this->peopletag->homeUrl(), 303);
|
common_redirect($this->peopletag->homeUrl(), 303);
|
||||||
}
|
}
|
||||||
|
@@ -86,12 +86,6 @@ class PublicAction extends SitestreamAction
|
|||||||
$ibs->show();
|
$ibs->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
$p = Profile::current();
|
|
||||||
|
|
||||||
if (!common_config('performance', 'high')) {
|
|
||||||
$cloud = new PublicTagCloudSection($this);
|
|
||||||
$cloud->show();
|
|
||||||
}
|
|
||||||
$feat = new FeaturedUsersSection($this);
|
$feat = new FeaturedUsersSection($this);
|
||||||
$feat->show();
|
$feat->show();
|
||||||
}
|
}
|
||||||
@@ -99,27 +93,33 @@ class PublicAction extends SitestreamAction
|
|||||||
/**
|
/**
|
||||||
* Output <head> elements for RSS and Atom feeds
|
* Output <head> elements for RSS and Atom feeds
|
||||||
*
|
*
|
||||||
* @return void
|
* @return array
|
||||||
*/
|
*/
|
||||||
function getFeeds()
|
function getFeeds()
|
||||||
{
|
{
|
||||||
return array(new Feed(Feed::JSON,
|
return [
|
||||||
common_local_url('ApiTimelinePublic',
|
new Feed(Feed::ATOM,
|
||||||
array('format' => 'as')),
|
common_local_url('ApiTimelinePublic',
|
||||||
// TRANS: Link description for public timeline feed.
|
array('format' => 'atom')),
|
||||||
_('Public Timeline Feed (Activity Streams JSON)')),
|
// TRANS: Link description for public timeline feed.
|
||||||
new Feed(Feed::RSS1, common_local_url('publicrss'),
|
_('Public Timeline Feed (Atom)')
|
||||||
// TRANS: Link description for public timeline feed.
|
),
|
||||||
_('Public Timeline Feed (RSS 1.0)')),
|
new Feed(Feed::JSON,
|
||||||
new Feed(Feed::RSS2,
|
common_local_url('ApiTimelinePublic',
|
||||||
common_local_url('ApiTimelinePublic',
|
array('format' => 'as')),
|
||||||
array('format' => 'rss')),
|
// TRANS: Link description for public timeline feed.
|
||||||
// TRANS: Link description for public timeline feed.
|
_('Public Timeline Feed (Activity Streams JSON)')
|
||||||
_('Public Timeline Feed (RSS 2.0)')),
|
),
|
||||||
new Feed(Feed::ATOM,
|
new Feed(Feed::RSS1, common_local_url('publicrss'),
|
||||||
common_local_url('ApiTimelinePublic',
|
// TRANS: Link description for public timeline feed.
|
||||||
array('format' => 'atom')),
|
_('Public Timeline Feed (RSS 1.0)')
|
||||||
// TRANS: Link description for public timeline feed.
|
),
|
||||||
_('Public Timeline Feed (Atom)')));
|
new Feed(Feed::RSS2,
|
||||||
|
common_local_url('ApiTimelinePublic',
|
||||||
|
array('format' => 'rss')),
|
||||||
|
// TRANS: Link description for public timeline feed.
|
||||||
|
_('Public Timeline Feed (RSS 2.0)')
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user