forked from GNUsocial/gnu-social
Compare commits
1884 Commits
v1.1.3rele
...
v1.20.9rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
b2cfbded2e | ||
|
|
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 | ||
|
|
346a73c36f | ||
|
|
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 | ||
|
|
6336248d71 | ||
|
|
67aff528f5 | ||
|
|
93f5043230 | ||
|
|
80f7a5f025 | ||
|
|
4239c952d2 | ||
|
|
e69f878241 | ||
|
|
6d3aa3276a | ||
|
|
e3e3a91734 | ||
|
|
54da2526ed | ||
|
|
99f2aba6e1 | ||
|
|
128a00c4ab | ||
|
|
1d0a448e07 | ||
|
|
731fd01139 | ||
|
|
3ef573f67c | ||
|
|
e6f07d8554 | ||
|
|
31c9b2c1d8 | ||
|
|
9319033ff0 | ||
|
|
0eb5122817 | ||
|
|
6bcfc73175 | ||
|
|
d672547112 | ||
|
|
e16f7d04a8 | ||
|
|
b59dacb806 | ||
|
|
5f7032dfee | ||
|
|
c67b89e56b | ||
|
|
ce803f6d06 | ||
|
|
1edb1bbc17 | ||
|
|
893d117309 | ||
|
|
0c17c32267 | ||
|
|
23e66bef64 | ||
|
|
d16a883e17 | ||
|
|
b23cc7465f | ||
|
|
afbdcf8938 | ||
|
|
a838c90951 | ||
|
|
f68d1ade3f | ||
|
|
543d968b81 | ||
|
|
a361fdbd77 | ||
|
|
73dbc5ca1b | ||
|
|
d9b649642d | ||
|
|
d2c11925bf | ||
|
|
5fbb01130a | ||
|
|
47dc15c9f6 | ||
|
|
d6bf90cfb7 | ||
|
|
ade4518ae4 | ||
|
|
422d475e44 | ||
|
|
501d081d3b | ||
|
|
d2507a6266 | ||
|
|
46829c6d3c | ||
|
|
2d1b70c94d | ||
|
|
2301862ae6 | ||
|
|
dcb7ce36d8 | ||
|
|
e2a090c9cc | ||
|
|
c23c3a4f53 | ||
|
|
4bf26eff4c | ||
|
|
be14e15dac | ||
|
|
fbcca62ae1 | ||
|
|
8ef2abf30b | ||
|
|
799c2e47fe | ||
|
|
be35975b12 | ||
|
|
557ad2d1fd | ||
|
|
c7c34ec05a | ||
|
|
83f679fb57 | ||
|
|
3cef75bcac | ||
|
|
e5ad98e601 | ||
|
|
5dce08d068 | ||
|
|
f10625f8bc | ||
|
|
338df7e35b | ||
|
|
c8753353ed | ||
|
|
913595780f | ||
|
|
1471defff3 | ||
|
|
05fea4cdc6 | ||
|
|
2198f39597 | ||
|
|
6f2fbd448d | ||
|
|
38a187b93e | ||
|
|
7fdcbd56d5 | ||
|
|
70d85c58e2 | ||
|
|
67dfc0a046 | ||
|
|
b9d35659c8 | ||
|
|
733debd9b3 | ||
|
|
8806cce735 | ||
|
|
dd229e855a | ||
|
|
893d888152 | ||
|
|
49b7648fea | ||
|
|
d0b2d86ca1 | ||
|
|
9f961597c6 | ||
|
|
a61235086b | ||
|
|
ec257d940a | ||
|
|
dcf29c2a07 | ||
|
|
eaa394ed7d | ||
|
|
a614205663 | ||
|
|
2c5cba28b6 | ||
|
|
7c90d7022b | ||
|
|
ef5ed10eb9 | ||
|
|
cd71188d3a | ||
|
|
a30d34be7f | ||
|
|
d98784e059 | ||
|
|
3dea259f52 | ||
|
|
2938b3e960 | ||
|
|
13cf744fb3 | ||
|
|
2686635f60 | ||
|
|
1126f70786 | ||
|
|
7c7f2f890f | ||
|
|
d6664f5735 | ||
|
|
58e852f7f7 | ||
|
|
6bec22ea4e | ||
|
|
25f623565a | ||
|
|
098c8b1df4 | ||
|
|
55546a5aab | ||
|
|
7aca4e7463 | ||
|
|
41e36e1f28 | ||
|
|
1f01356076 | ||
|
|
60804d1902 | ||
|
|
d5ecbd05a1 | ||
|
|
9960714896 | ||
|
|
90045d66ea | ||
|
|
2c83614170 | ||
|
|
349dba8be0 | ||
|
|
e903bd0bc3 | ||
|
|
b1ed1f48ea | ||
|
|
25c15119bc | ||
|
|
84930f89f9 | ||
|
|
19b743a9f5 | ||
|
|
9fcfb7cb1d | ||
|
|
6a4aa34b0c | ||
|
|
40cffb9463 | ||
|
|
a2b914ce60 | ||
|
|
43abfe659b | ||
|
|
367fc054dc | ||
|
|
771f08b3c7 | ||
|
|
5167b1fa40 | ||
|
|
c6ae883ad2 | ||
|
|
a5c1b063fd | ||
|
|
689e277c62 | ||
|
|
36f099958c | ||
|
|
cb40f72c7e | ||
|
|
f708a5b016 | ||
|
|
efd2326a29 | ||
|
|
5b11238010 | ||
|
|
6b31feb70f | ||
|
|
a6898b033d | ||
|
|
c0851d59f5 | ||
|
|
fb7f572eed | ||
|
|
7e6783bb8f | ||
|
|
daea5647b6 | ||
|
|
9b3cbb373e | ||
|
|
efe23ed404 | ||
|
|
05439831e7 | ||
|
|
06e325d61b | ||
|
|
d94f9031ff | ||
|
|
10f16e4f32 | ||
|
|
c459bded53 | ||
|
|
fb15dc5080 | ||
|
|
bf38fb7bef | ||
|
|
7c80c9a1f9 | ||
|
|
dfc11f99ad | ||
|
|
bb0cb9b3f6 | ||
|
|
d73c264e25 | ||
|
|
34093388a7 | ||
|
|
a47563cf3d | ||
|
|
03d2b680f8 | ||
|
|
52778e1882 | ||
|
|
42545c6625 | ||
|
|
e69715005d | ||
|
|
c01982c917 | ||
|
|
aa76e5863f | ||
|
|
b8d1e1f4a6 | ||
|
|
884aeb4d2e | ||
|
|
473f893d04 | ||
|
|
76c8139054 | ||
|
|
a48055a3cc | ||
|
|
c0b0f8e2f9 | ||
|
|
e447964639 | ||
|
|
b1b6a0a69c | ||
|
|
a888294135 | ||
|
|
ca0c792ed3 | ||
|
|
48e1a2431b | ||
|
|
b15434375c | ||
|
|
9614aba0e1 | ||
|
|
fef52d7b51 | ||
|
|
a9d18a077e | ||
|
|
1cec627d72 | ||
|
|
4e50717e12 | ||
|
|
ef005987a1 | ||
|
|
1121b38eb1 | ||
|
|
89dd44bf3e | ||
|
|
81f9a59f25 | ||
|
|
d0e2f8745d | ||
|
|
3f9c1c142a | ||
|
|
45446f17ad | ||
|
|
be1759f112 | ||
|
|
d3a4a2225f | ||
|
|
81bf0fd261 | ||
|
|
f74d2d555c | ||
|
|
d13454fb84 | ||
|
|
5999171c11 | ||
|
|
45b523bada | ||
|
|
21cc737f5c | ||
|
|
9accd953e4 | ||
|
|
64e74d527f | ||
|
|
c393bc9563 | ||
|
|
912d65c767 | ||
|
|
fa8e02b832 | ||
|
|
de047f9727 | ||
|
|
80dc2788dd | ||
|
|
477d71c0bf | ||
|
|
84dda697d6 | ||
|
|
73992a1ed8 | ||
|
|
9eea255c79 | ||
|
|
358684a5ed | ||
|
|
385705c65b | ||
|
|
15d12b209d | ||
|
|
7715ea993b | ||
|
|
f768de4b46 | ||
|
|
cae344b67b | ||
|
|
6c46a93a81 | ||
|
|
486a02d60d | ||
|
|
11b925c4ca | ||
|
|
c1655c2c0f | ||
|
|
b0416ae592 | ||
|
|
78346af572 | ||
|
|
bdc38a7204 | ||
|
|
6dc0477c00 | ||
|
|
deda83fdef | ||
|
|
4678546d33 | ||
|
|
a85a08ff35 | ||
|
|
0797ee0871 | ||
|
|
3019f8f23f | ||
|
|
fdfa71a033 | ||
|
|
c559b8ce2a | ||
|
|
f53ebdeadb | ||
|
|
1f76c1e4a9 | ||
|
|
2b67b53112 | ||
|
|
44c10bb2aa | ||
|
|
a1530b0e68 | ||
|
|
8df38df5cb | ||
|
|
16088d9439 | ||
|
|
bc0a903bd4 | ||
|
|
818fb05cfe | ||
|
|
e5019c3858 | ||
|
|
b570f0d3cb | ||
|
|
2af9de4f23 | ||
|
|
b530d385bc | ||
|
|
0caf0612d0 | ||
|
|
6e49281adb | ||
|
|
2f1bfe126b | ||
|
|
c173c4faa5 | ||
|
|
59e75ef966 | ||
|
|
f092026541 | ||
|
|
df00a88cb4 | ||
|
|
bacd49a6a8 | ||
|
|
0781c2a7b9 | ||
|
|
b7c849b5b0 | ||
|
|
83cb1dfa68 | ||
|
|
6834f355f2 | ||
|
|
99261e0781 | ||
|
|
53339ff463 | ||
|
|
331abf173b | ||
|
|
f699ffeb8a | ||
|
|
cf7d2f4d0f | ||
|
|
0ddaa6ff75 | ||
|
|
0482b7de8e | ||
|
|
24d9d76644 | ||
|
|
1e5770bbcf | ||
|
|
adba38ce20 | ||
|
|
45dd343126 | ||
|
|
29b45bb87a | ||
|
|
8ab98b72ac | ||
|
|
377947c57f | ||
|
|
1d26fedf12 | ||
|
|
494746e665 | ||
|
|
a5fd4fde25 | ||
|
|
b38a789005 | ||
|
|
818aaa0578 | ||
|
|
961725205d | ||
|
|
ee305891c4 | ||
|
|
3e7e3de554 | ||
|
|
5c262a788d | ||
|
|
3720e37f06 | ||
|
|
99da1ebe41 | ||
|
|
3ed632decf | ||
|
|
e75472f460 | ||
|
|
eceafb84de | ||
|
|
14bd6daab1 | ||
|
|
e49e113140 | ||
|
|
3658774429 | ||
|
|
f4feef477b | ||
|
|
b696fb4eb1 | ||
|
|
8c28e54ccc | ||
|
|
dbe5d72e4c | ||
|
|
d07640caba | ||
|
|
e4a1dff98d | ||
|
|
e94017a552 | ||
|
|
a1b509bb0b | ||
|
|
8d331b0f35 | ||
|
|
543a7e421e | ||
|
|
c826fe0af4 | ||
|
|
bd6efa0e45 | ||
|
|
f24cdf4a80 | ||
|
|
1a46d86ca6 | ||
|
|
93c614c184 | ||
|
|
c1f22f106b | ||
|
|
5b2b969a77 | ||
|
|
8acf930c45 | ||
|
|
b13f8df79b | ||
|
|
63fff7ef47 | ||
|
|
87ae5292b8 | ||
|
|
e498bc6b7b | ||
|
|
7fbf72f9c1 | ||
|
|
42dff2742a | ||
|
|
67801a5566 | ||
|
|
5ef10a14ef | ||
|
|
c3c5a9974d | ||
|
|
55aa68b941 | ||
|
|
fbec7c4e75 | ||
|
|
d1e609a886 | ||
|
|
f143925931 | ||
|
|
d13483ca20 | ||
|
|
33194b3cff | ||
|
|
28cd5640c1 | ||
|
|
0463d96392 | ||
|
|
4e0ed61f7c | ||
|
|
e6f2676c5c | ||
|
|
c48871cf1b | ||
|
|
6255e1dca3 | ||
|
|
801ca3531b | ||
|
|
3eebf2a353 | ||
|
|
cd2695190d | ||
|
|
1f02dc639e | ||
|
|
be58fd64f5 | ||
|
|
6505504411 | ||
|
|
d4be5349b3 | ||
|
|
9e5c71e701 | ||
|
|
c02f23e63f | ||
|
|
5d4b1d0b88 | ||
|
|
839ae571d8 | ||
|
|
e7308b0ecb | ||
|
|
94392ab00c | ||
|
|
05d3622939 | ||
|
|
6924bb1d29 | ||
|
|
a9b5519293 | ||
|
|
4d179c6b0c | ||
|
|
47c7e1b875 | ||
|
|
f1c4c64cd9 | ||
|
|
346e34e543 | ||
|
|
4352d1739d | ||
|
|
1a1e44cdfd | ||
|
|
7b2036a4b5 | ||
|
|
b596391fcd | ||
|
|
d6ac002639 | ||
|
|
4a8e936e19 | ||
|
|
0fd2ad649e | ||
|
|
4b22b0c42a | ||
|
|
6d9f390ba8 | ||
|
|
da2f179ae9 | ||
|
|
e577e883f4 | ||
|
|
59d3bbe037 | ||
|
|
d45457e4a9 | ||
|
|
1946197a1c | ||
|
|
32549cfd8c | ||
|
|
2c5460eb0e | ||
|
|
31c8416a8f | ||
|
|
956e053da6 | ||
|
|
792b62874e | ||
|
|
0b4b0de412 | ||
|
|
1c25cffbd8 | ||
|
|
3d66d960a1 | ||
|
|
8b78e01d4c | ||
|
|
64f2f3d976 | ||
|
|
8ad6b8809a | ||
|
|
e10691abea | ||
|
|
9a75778b29 | ||
|
|
3471213d1c | ||
|
|
ab93bb009c | ||
|
|
df8c14d66a | ||
|
|
701f6ff608 | ||
|
|
6a16939830 | ||
|
|
bf0df016e5 | ||
|
|
de7e8c59e8 | ||
|
|
fb537fb7f4 | ||
|
|
065e23b1c4 | ||
|
|
00ace6c2df | ||
|
|
f7a1c8a94c | ||
|
|
34b25e6afc | ||
|
|
b4b57bba54 | ||
|
|
bda30a92bc | ||
|
|
7266a968f9 | ||
|
|
f467b89f40 | ||
|
|
3bddf01350 | ||
|
|
c19964094b | ||
|
|
b374e5f08b | ||
|
|
df0f9547b5 | ||
|
|
7df8a6b731 | ||
|
|
aa3028e5d9 | ||
|
|
3251ef3b51 | ||
|
|
95d415257a | ||
|
|
0dc7fcce5b | ||
|
|
336f099241 | ||
|
|
fe328ae5e4 | ||
|
|
cf6e06a5dd | ||
|
|
0dfafe2567 | ||
|
|
26a6eca94e | ||
|
|
f4309ed715 | ||
|
|
e02c10a589 | ||
|
|
54325e266f | ||
|
|
ad4beb9091 | ||
|
|
10973dcf69 | ||
|
|
86106b890a | ||
|
|
4fc2b2584b | ||
|
|
34ce2f6cfa | ||
|
|
f6df44ea85 | ||
|
|
7adf1c99fc | ||
|
|
7f1ce07e9f | ||
|
|
fab745c6d6 | ||
|
|
6606781916 | ||
|
|
5ba6be1a87 | ||
|
|
df19791a8f | ||
|
|
8b0fdfb4a0 | ||
|
|
7cf6aaecd0 | ||
|
|
66289d3e76 | ||
|
|
6772d991ae | ||
|
|
f61187a210 | ||
|
|
bceece3bb9 | ||
|
|
b0bf620c61 | ||
|
|
29847f172f | ||
|
|
d7a8ee99af | ||
|
|
998db39b1a | ||
|
|
ad5d5f8054 | ||
|
|
08be0e5c67 | ||
|
|
c0ef167514 | ||
|
|
2f836e2a59 | ||
|
|
17a65ff873 | ||
|
|
7f4b51e246 | ||
|
|
4bc0b374bc | ||
|
|
bd00ef839d | ||
|
|
556d6e198f | ||
|
|
cf916141d0 | ||
|
|
feb6b636f4 | ||
|
|
12d77ac3e4 | ||
|
|
4a31e4992d | ||
|
|
6026dcaed1 | ||
|
|
62c4ffe889 | ||
|
|
b76461fc78 | ||
|
|
0ac71c2b7b | ||
|
|
83c112e24b | ||
|
|
306df3dc3b | ||
|
|
ace47a4512 | ||
|
|
48f31928e9 | ||
|
|
4904c2bc10 | ||
|
|
cc26c4cb1a | ||
|
|
90945e548b | ||
|
|
71119e4980 | ||
|
|
3e830dad37 | ||
|
|
d8092207c0 | ||
|
|
bb0faaea56 | ||
|
|
f5ed66280b | ||
|
|
2b4a6c7dd7 | ||
|
|
ef4c11d262 | ||
|
|
0d39337683 | ||
|
|
67c0c1b6c5 | ||
|
|
0baa9debbc | ||
|
|
1644608376 | ||
|
|
0e91a38c9c | ||
|
|
0f938ff234 | ||
|
|
c2ea85a5e2 | ||
|
|
1be376cf87 | ||
|
|
1eff108561 | ||
|
|
2addf8e456 | ||
|
|
ef4e61c91b | ||
|
|
4ea396f871 | ||
|
|
edd62e58fd | ||
|
|
8d26d83d7a | ||
|
|
2dd968f94e | ||
|
|
d5d8068632 | ||
|
|
5f0412b9ee | ||
|
|
289116cb64 | ||
|
|
20592f184d | ||
|
|
42c653a9d0 | ||
|
|
c114c6bbad | ||
|
|
129bd1bf03 | ||
|
|
d659e0aaf9 | ||
|
|
8d1105fe73 | ||
|
|
441e2c8d34 | ||
|
|
4fecda58ff | ||
|
|
376d545082 | ||
|
|
c498db147a | ||
|
|
10bb4cb659 | ||
|
|
b537696370 | ||
|
|
6d9ea620a3 | ||
|
|
a06dc57621 | ||
|
|
3e16e31080 | ||
|
|
831e9db7ec | ||
|
|
4479d780e5 | ||
|
|
334a0d56e7 | ||
|
|
8bab642cc7 | ||
|
|
b7edac2610 | ||
|
|
c95f74018d | ||
|
|
fbe0e68617 | ||
|
|
5b847eff12 | ||
|
|
bca4bb8373 | ||
|
|
b01484a0a3 | ||
|
|
5c4a7a1052 | ||
|
|
1eba33590b | ||
|
|
70695a1463 | ||
|
|
1630424797 | ||
|
|
b33b40db45 | ||
|
|
38c84a92c7 | ||
|
|
5d548d157f | ||
|
|
abb8d1273e | ||
|
|
4f0fae9e90 | ||
|
|
11810bbf54 | ||
|
|
47db1ab063 | ||
|
|
f09a82268f | ||
|
|
b95b318052 | ||
|
|
6aba21fcd8 | ||
|
|
fa1e4620cf | ||
|
|
aa4d880148 | ||
|
|
96e0819f00 | ||
|
|
c5bdf6924d | ||
|
|
64ac344efa | ||
|
|
b9971e8a80 | ||
|
|
1e3cf08d82 | ||
|
|
dbfb698859 | ||
|
|
96fb18da3f | ||
|
|
d0e7203d88 | ||
|
|
acd4980ab4 | ||
|
|
844670f88d | ||
|
|
65184782aa | ||
|
|
f29daa22b6 | ||
|
|
dbdac9cfbe | ||
|
|
e40014b4de | ||
|
|
c83deecba2 | ||
|
|
5f999e84d8 | ||
|
|
507f9a28c0 | ||
|
|
7ccd36849e | ||
|
|
f345f1d605 | ||
|
|
deb5275c7a | ||
|
|
959f971a65 | ||
|
|
9f83e60f25 | ||
|
|
0e32729e59 | ||
|
|
c950f18546 | ||
|
|
96e0867d4c | ||
|
|
45b24286e5 | ||
|
|
f513ceac7d | ||
|
|
5c768d7ef7 | ||
|
|
4b7c904fe0 | ||
|
|
a3ddc4ec0c | ||
|
|
3ca4af6868 | ||
|
|
ba623d2b4e | ||
|
|
a9b1b60a97 | ||
|
|
d7b58491ce | ||
|
|
a74572b469 | ||
|
|
6ac8b845bf | ||
|
|
fe4c8a771b | ||
|
|
0aa759fab7 | ||
|
|
2edf535ecd | ||
|
|
85d5cfede5 | ||
|
|
e58c529c53 | ||
|
|
2207eacc92 | ||
|
|
fed0895d98 | ||
|
|
1b81131c51 | ||
|
|
e1de6e0aa9 | ||
|
|
ebbb9a8990 | ||
|
|
54e87dd2c3 | ||
|
|
3ae81f095c | ||
|
|
03c68d283d | ||
|
|
4c2bc465a0 | ||
|
|
fae7bc0bc0 | ||
|
|
dc36621dc2 | ||
|
|
21979bb7d7 | ||
|
|
033ed7e4aa | ||
|
|
cd22be3374 | ||
|
|
ddfb56d920 | ||
|
|
983fd75ec9 | ||
|
|
2030ddfc79 | ||
|
|
439b466979 | ||
|
|
d1f1063900 | ||
|
|
123bb445db | ||
|
|
8649591626 | ||
|
|
3e1a6a65e6 | ||
|
|
4b31bc3fd2 | ||
|
|
df21c3c95d | ||
|
|
df46f123dd | ||
|
|
fc3f1f6942 | ||
|
|
677f0ac479 | ||
|
|
303fa91720 | ||
|
|
c7e08195e4 | ||
|
|
d9d74ca96c | ||
|
|
aa5bbdf6e5 | ||
|
|
3b1792c8b5 | ||
|
|
e4892d21b1 | ||
|
|
8edc5148d9 | ||
|
|
63fd35dffa | ||
|
|
b43294ec6f | ||
|
|
a4a37d6fc9 | ||
|
|
626333a59e | ||
|
|
2c8536dbf0 | ||
|
|
401b774c2f | ||
|
|
d260808cd3 | ||
|
|
79c40bc73b | ||
|
|
b6aeff89c4 | ||
|
|
236bf0b0f5 | ||
|
|
005c108118 | ||
|
|
5b307c0417 | ||
|
|
65adefe170 | ||
|
|
4b69ef41e2 | ||
|
|
e379c49d49 | ||
|
|
c8a907c828 | ||
|
|
3f4d4cb7a0 | ||
|
|
67e7bc55ea | ||
|
|
7834e67583 | ||
|
|
297d68f36c | ||
|
|
0e588bdeca | ||
|
|
1dac0e709a | ||
|
|
b209276e72 | ||
|
|
5726459629 | ||
|
|
0926316a76 | ||
|
|
3255e2e1b8 | ||
|
|
32f77dbf05 | ||
|
|
89d3d9b2ce | ||
|
|
77951647ce | ||
|
|
238d2a3876 | ||
|
|
fe9457daea | ||
|
|
174586bd51 | ||
|
|
cae43344ec | ||
|
|
18f07a48e8 | ||
|
|
37f2da03e1 | ||
|
|
45bc192625 | ||
|
|
a793d211d2 | ||
|
|
b4c51b2d39 | ||
|
|
9728270acd | ||
|
|
5d91c9a820 | ||
|
|
2ad7c4313d | ||
|
|
6376b78a80 | ||
|
|
a9f879c2ba | ||
|
|
b24191f9f9 | ||
|
|
3154302b53 | ||
|
|
61ed36e446 | ||
|
|
dd149a76f3 | ||
|
|
2dfd34b12d | ||
|
|
55655ba319 | ||
|
|
827dffb94c | ||
|
|
2d3f1ef520 | ||
|
|
0bdbb32f3b | ||
|
|
5dc718c54d | ||
|
|
5a2d760177 | ||
|
|
499d4aadbc | ||
|
|
216a04df86 | ||
|
|
3013b84e98 | ||
|
|
2d81df4760 | ||
|
|
180958185f | ||
|
|
ee6096cca8 | ||
|
|
3902dc963a | ||
|
|
0ba53edd96 | ||
|
|
ec19661312 | ||
|
|
d7fd6bac72 | ||
|
|
af1b0915f4 | ||
|
|
6afa091dca | ||
|
|
f4ed171397 | ||
|
|
2970333adb | ||
|
|
57f26a97fb | ||
|
|
4238875ebe | ||
|
|
684b9419a0 | ||
|
|
2aed59a02a | ||
|
|
9b461db4da | ||
|
|
184293c634 | ||
|
|
bc9e3b1843 | ||
|
|
30a4393afa | ||
|
|
aab7667cd5 | ||
|
|
833abbb191 | ||
|
|
e6d7534a88 | ||
|
|
db726ca294 | ||
|
|
7c68537b06 | ||
|
|
db9f68e651 | ||
|
|
66a1d63dd0 | ||
|
|
aba38d5586 | ||
|
|
1244e8d929 | ||
|
|
2e77a83816 | ||
|
|
dac617d95a | ||
|
|
88f7bb1ed5 | ||
|
|
ae73baf4ee | ||
|
|
0c6fe78a73 | ||
|
|
b8f52965a9 | ||
|
|
d52b7e3124 | ||
|
|
80bc7f0e25 | ||
|
|
5b7deee0cc | ||
|
|
3a6c98ff16 | ||
|
|
a09cf51b99 | ||
|
|
21a12a2f60 | ||
|
|
118a4f56ab | ||
|
|
34b6d37266 | ||
|
|
d6e56924fe | ||
|
|
ad3b62cf2f | ||
|
|
0e24709989 | ||
|
|
edb73ec480 | ||
|
|
02418cffd8 | ||
|
|
0bd0c65b87 | ||
|
|
b209dcf8a7 | ||
|
|
96a7bf2b90 | ||
|
|
604ed1fd9a | ||
|
|
9ad9b91efb | ||
|
|
404d5781fc | ||
|
|
52de57e2f6 | ||
|
|
4b83d62750 | ||
|
|
a541533e04 | ||
|
|
917a547f91 | ||
|
|
d448275713 | ||
|
|
4354ce21d1 | ||
|
|
dc5dd69f2e | ||
|
|
ea75e1c29c | ||
|
|
7f30e61402 | ||
|
|
3c86542a40 | ||
|
|
476197569f | ||
|
|
1e07f8c045 | ||
|
|
57c87088d4 | ||
|
|
f4b0756e70 | ||
|
|
a597b28001 | ||
|
|
5f74ec6782 | ||
|
|
e06553b15b | ||
|
|
84a65c7189 | ||
|
|
91c1ab6017 | ||
|
|
c77bce12e5 | ||
|
|
76004660e9 | ||
|
|
c1e6e4e65b | ||
|
|
b434243416 | ||
|
|
60e7dc1e39 | ||
|
|
de1d49865c | ||
|
|
cd6ad8571f | ||
|
|
86ed4ac603 | ||
|
|
8056aec93e | ||
|
|
dc9342f184 | ||
|
|
31bcf8cfa2 | ||
|
|
a416abb940 | ||
|
|
7b04ee6a9b | ||
|
|
a04b1cda45 | ||
|
|
b0abce9bc8 | ||
|
|
c6f58d432c | ||
|
|
abde7a2682 | ||
|
|
05b814ce68 | ||
|
|
ad49158fb5 | ||
|
|
266b032b17 | ||
|
|
7ce32619cc | ||
|
|
5b09a150bc | ||
|
|
e0084a6fdf | ||
|
|
b609a3610f | ||
|
|
6f62adedfc | ||
|
|
9fdf6474f8 | ||
|
|
beba2a25d0 | ||
|
|
e10d081a56 | ||
|
|
6cd7a4a400 | ||
|
|
5933056a5b | ||
|
|
d6d06c8cbb | ||
|
|
712a6d49d0 | ||
|
|
da168674f9 | ||
|
|
8d2504a809 | ||
|
|
be0c10e8f6 | ||
|
|
992fe6896f | ||
|
|
8d516d7f08 | ||
|
|
2dd979d3f8 | ||
|
|
a093dea38c | ||
|
|
9045575e62 | ||
|
|
9f82da07f1 | ||
|
|
53e820b466 | ||
|
|
cfaaf3c13c | ||
|
|
47ef917f62 | ||
|
|
a6e299a2fc | ||
|
|
ba5a43f2f9 | ||
|
|
f1d9d8a6ed | ||
|
|
647171e089 | ||
|
|
fd2efbc6f8 | ||
|
|
2d44400cfc | ||
|
|
673bef2fda | ||
|
|
94d54ebc29 | ||
|
|
44dc00a58c | ||
|
|
cd23c78800 | ||
|
|
01a4ab30dc | ||
|
|
c10a4cf6d2 | ||
|
|
e868ac41cd | ||
|
|
c5a5eaf288 | ||
|
|
ac98600640 | ||
|
|
7d524307d2 | ||
|
|
9101a1db3d | ||
|
|
2a1be57470 | ||
|
|
e439ace944 | ||
|
|
fae79b5812 | ||
|
|
bb29d18017 | ||
|
|
5929b629e5 | ||
|
|
76396041e2 | ||
|
|
64fbc93217 | ||
|
|
24b1e26406 | ||
|
|
961031bc28 | ||
|
|
ad453785f0 | ||
|
|
08bd4fa6a8 | ||
|
|
3900a739b9 | ||
|
|
55b2d124bc | ||
|
|
a964ea61cd | ||
|
|
c037f04d17 | ||
|
|
7c4e550e31 | ||
|
|
204f6bb503 | ||
|
|
6c4985476e | ||
|
|
9a92b58057 | ||
|
|
f8877e015b | ||
|
|
50c297bcbe | ||
|
|
6a36121a56 | ||
|
|
f9d82a6ac5 | ||
|
|
e567406c9f | ||
|
|
1ab4c9998a | ||
|
|
d6924f7680 | ||
|
|
76432b958b | ||
|
|
e46b2803a7 | ||
|
|
1cbf2510e7 | ||
|
|
8cc85f684b | ||
|
|
b5b7a27f9b | ||
|
|
06f60b57c1 | ||
|
|
37e8b027f9 | ||
|
|
ed248f7f5a | ||
|
|
90565cc44d | ||
|
|
9fb3ea3ce6 | ||
|
|
d63bca9d3c | ||
|
|
9b8ac2d404 | ||
|
|
65f1f74f2b | ||
|
|
43cec8eaac | ||
|
|
2103075ffa | ||
|
|
f939485b52 | ||
|
|
77957372ab | ||
|
|
33dc06ae21 | ||
|
|
d0458b824a | ||
|
|
45ee2060fa | ||
|
|
6919dda958 | ||
|
|
acdcb2ad8d | ||
|
|
edef6f929a | ||
|
|
62c6ed58ba | ||
|
|
ed3022adc1 | ||
|
|
3b6a424c9f | ||
|
|
9054bb69e9 | ||
|
|
5424c82423 | ||
|
|
3f3482f017 | ||
|
|
d5a24da167 | ||
|
|
030b570051 | ||
|
|
3a74f49182 | ||
|
|
748bd825e7 | ||
|
|
e6507a0f18 | ||
|
|
1864a9de38 | ||
|
|
a25d952ef9 | ||
|
|
9e1d4bfbf0 | ||
|
|
fde3b99e8e | ||
|
|
29620619b5 | ||
|
|
46cf5aa2a4 | ||
|
|
ee9176f20d | ||
|
|
1d11153396 | ||
|
|
7c373edf4d | ||
|
|
41fe435553 | ||
|
|
01cbe744b6 | ||
|
|
e32cd2dd15 | ||
|
|
39462c3a2e | ||
|
|
e9a6d5be51 | ||
|
|
fca53a56b4 | ||
|
|
a03249dd99 | ||
|
|
437dc3d713 | ||
|
|
ea076a8783 | ||
|
|
965cd92a72 | ||
|
|
204ebe607d | ||
|
|
267a49103e | ||
|
|
a42d74a238 | ||
|
|
f9c51c2478 | ||
|
|
776b82e6e8 | ||
|
|
8a002e98bc | ||
|
|
4fc62a8bf5 | ||
|
|
3bdcdfd114 | ||
|
|
f7769c17b5 | ||
|
|
76c9971c31 | ||
|
|
e46dcc0cc4 | ||
|
|
9dc8250956 | ||
|
|
3a910d8c8c | ||
|
|
e203271d95 | ||
|
|
6267e7a930 | ||
|
|
d76d37340a | ||
|
|
871912a00a | ||
|
|
628e7fa583 | ||
|
|
15643c802b | ||
|
|
814696c202 | ||
|
|
50070c9b0a | ||
|
|
06503cc11b | ||
|
|
daaafd86e2 | ||
|
|
9e52b6f2d1 | ||
|
|
fae8e38616 | ||
|
|
4cba7a4002 | ||
|
|
9712a92853 | ||
|
|
28eb441812 | ||
|
|
3c2a720b21 | ||
|
|
6478034e92 | ||
|
|
faf14197cd | ||
|
|
b63054cb1d | ||
|
|
4de125dd84 | ||
|
|
268b901048 | ||
|
|
136c3140c2 | ||
|
|
7e90103f21 | ||
|
|
d4fc064e44 | ||
|
|
623a7eee57 | ||
|
|
57943cad99 | ||
|
|
c5f79fd2f3 | ||
|
|
e212f2ae77 | ||
|
|
a39f51c044 | ||
|
|
8abf96cfd8 | ||
|
|
b0a598ba7b | ||
|
|
e269a3fad9 | ||
|
|
47c83f4c49 | ||
|
|
1635d459ec | ||
|
|
77db161aca | ||
|
|
b3667c72c7 | ||
|
|
e3b1d401fd | ||
|
|
ad7cd155fb | ||
|
|
882ce56cf4 | ||
|
|
29e1203609 | ||
|
|
a3011febdf | ||
|
|
6e28524647 | ||
|
|
c26e08d6a6 | ||
|
|
9376a6d75a | ||
|
|
8ad81a6aa3 | ||
|
|
c00b2ecc4b | ||
|
|
dd2fb27316 | ||
|
|
bc7eb792f4 | ||
|
|
abfa052861 | ||
|
|
dbfc8092d7 | ||
|
|
6137d301be | ||
|
|
af87552e04 | ||
|
|
94f5247f91 | ||
|
|
dee4ca37ab | ||
|
|
b24d711f55 | ||
|
|
50f0235654 | ||
|
|
cafab14f2b | ||
|
|
63251fb9d0 | ||
|
|
fc9de94cbd | ||
|
|
f9698598c6 | ||
|
|
d1afc78124 | ||
|
|
ebdd792b6f | ||
|
|
ca19a5cd6d | ||
|
|
20145092ce | ||
|
|
5718f812d9 | ||
|
|
fe6498e7c8 | ||
|
|
5358fb3cce | ||
|
|
9449235765 | ||
|
|
a4739b0107 | ||
|
|
bdd15cfe63 | ||
|
|
26631bf9e6 | ||
|
|
551c69ed56 | ||
|
|
2b2ebfc254 | ||
|
|
fd121f371a | ||
|
|
c5da7306bd | ||
|
|
2bf0ec719d | ||
|
|
7e388e697d | ||
|
|
0726dcd06c | ||
|
|
c84b21008e | ||
|
|
6b9a8b7b19 | ||
|
|
e728e2aa81 | ||
|
|
2096c18e57 | ||
|
|
2cebbead75 | ||
|
|
a2ddcc124f | ||
|
|
82f9b6908c | ||
|
|
731d283159 | ||
|
|
1d85fd35a2 | ||
|
|
b4b8cb57b3 | ||
|
|
3294d704a4 | ||
|
|
f926e27a65 | ||
|
|
c31d6608a8 | ||
|
|
cd0b70dbc1 | ||
|
|
0e6b80ded3 | ||
|
|
19e7cf5f4a | ||
|
|
0200b1d784 | ||
|
|
6b717a6a69 | ||
|
|
925aacec1a | ||
|
|
bb8d377b91 | ||
|
|
f7176e7aef | ||
|
|
ef0385a25c | ||
|
|
5675f328b6 | ||
|
|
63ca11fc7d | ||
|
|
4a6f509aa5 | ||
|
|
d010c5a581 | ||
|
|
e1822c2b66 | ||
|
|
cd42ee7e85 | ||
|
|
6d72800098 | ||
|
|
2b58d6b774 | ||
|
|
7e2caa0bb1 | ||
|
|
51ecd6be15 | ||
|
|
7601e10b6a | ||
|
|
4210096a6f | ||
|
|
f642da201d | ||
|
|
0a0455b8d2 | ||
|
|
529b2f6613 | ||
|
|
f9f7c46751 | ||
|
|
8a119dc970 | ||
|
|
b75e88f65f | ||
|
|
1194c47c5d | ||
|
|
a55d1df585 | ||
|
|
0337a7b866 | ||
|
|
5f1e9e80c2 | ||
|
|
c5715bc756 | ||
|
|
e4a17fedc6 | ||
|
|
ee96a08700 | ||
|
|
4526c3f712 | ||
|
|
eefef44378 | ||
|
|
d7d96806a4 | ||
|
|
5e834e8119 | ||
|
|
cbabab273f | ||
|
|
0bd16b521c | ||
|
|
07d92acfd0 | ||
|
|
ef1f17fc2a | ||
|
|
5081477e95 | ||
|
|
f094918cf6 | ||
|
|
c94d9994d8 | ||
|
|
f6432fdf48 | ||
|
|
4fc4f91b9e | ||
|
|
9ab996d9e6 | ||
|
|
3cf5fe8795 | ||
|
|
94d3f50aee | ||
|
|
3dc30b6b8f | ||
|
|
8439efe77d | ||
|
|
a1098fa153 | ||
|
|
0b81fbd590 | ||
|
|
f92fe73d03 | ||
|
|
4f2095ea00 | ||
|
|
d9ed2a0fae | ||
|
|
4d6b5e70df | ||
|
|
a647a4f6b3 | ||
|
|
2821be2bce | ||
|
|
0ff11ac978 | ||
|
|
5a235ffbf9 | ||
|
|
642f7f850d | ||
|
|
1adf5f2863 | ||
|
|
3ee673ac91 | ||
|
|
20f8dd6565 | ||
|
|
940737a958 | ||
|
|
1350987e2e | ||
|
|
dc31a3d7d6 | ||
|
|
dcfcceb6f2 | ||
|
|
d24c4f349f | ||
|
|
c85e78ac3c | ||
|
|
7ddf586da7 | ||
|
|
4e9e3cf0d5 | ||
|
|
5bea746fa8 | ||
|
|
5c8e56e8d2 | ||
|
|
6f0f8cd6c7 | ||
|
|
2a32af084f | ||
|
|
6f76c8b59d | ||
|
|
88411fb1ca | ||
|
|
3302067aad | ||
|
|
0a2c51510c | ||
|
|
c79b9a2289 | ||
|
|
8cfe72c683 | ||
|
|
9ef224fceb | ||
|
|
af67f15cf2 | ||
|
|
e338931ffa | ||
|
|
502f26299b | ||
|
|
8a273eef20 | ||
|
|
fa080328cf | ||
|
|
fa3457f391 | ||
|
|
aa27c45230 | ||
|
|
f321c3c2ea | ||
|
|
9bb648739b | ||
|
|
3287ecc8d3 | ||
|
|
1e89540c3f | ||
|
|
5a3a3420e3 | ||
|
|
8ae1328e71 | ||
|
|
6f61b4488e | ||
|
|
474c8bef0a | ||
|
|
7aa1e02d06 | ||
|
|
b41c6824c5 | ||
|
|
05006f687a | ||
|
|
1ea876296d | ||
|
|
55894f02c7 | ||
|
|
32dacb9369 | ||
|
|
d6423bbbc8 | ||
|
|
1442ca16b4 | ||
|
|
1a1b992858 | ||
|
|
a452a3b1a0 | ||
|
|
3c5383b11c | ||
|
|
77190c9a87 | ||
|
|
75d45dace9 | ||
|
|
b604630a74 | ||
|
|
9deff7afaf | ||
|
|
4e682f3d88 | ||
|
|
196df7d8a4 | ||
|
|
98b65763b0 | ||
|
|
aefaef3ead | ||
|
|
be15ab47dc | ||
|
|
bc1d667784 | ||
|
|
395c2cc075 | ||
|
|
a6c03e3127 | ||
|
|
6080f6673e | ||
|
|
fab08278ea | ||
|
|
6b147175bb | ||
|
|
503c05b749 | ||
|
|
1303943424 | ||
|
|
8cf0628f28 | ||
|
|
c48a9191c8 | ||
|
|
38f977d2f3 | ||
|
|
45861c6d9c | ||
|
|
8abc2d3b8d | ||
|
|
0da7512597 | ||
|
|
13c331fa81 | ||
|
|
62596d462b | ||
|
|
f35ea45e09 | ||
|
|
72015d499f | ||
|
|
3755faf558 | ||
|
|
ff6969302b | ||
|
|
d7fd507d99 | ||
|
|
4c2bbf2354 | ||
|
|
22dbeaef29 | ||
|
|
9720fd8250 | ||
|
|
f6df1f1dd3 | ||
|
|
286b54e527 | ||
|
|
a4af51b5ba | ||
|
|
dcfb813066 | ||
|
|
fe9dc8e901 | ||
|
|
284705eeb8 | ||
|
|
ec4e432d55 | ||
|
|
8c933a6c06 | ||
|
|
325199b5e6 | ||
|
|
80bf185ad5 | ||
|
|
19bf975e56 | ||
|
|
1227d2d710 | ||
|
|
bece816ec7 | ||
|
|
7fdf2f50f4 | ||
|
|
746e658f3e | ||
|
|
caa0dd549e | ||
|
|
49cf19ccfe | ||
|
|
6abcc24834 | ||
|
|
fd53bb404f | ||
|
|
dceb67c247 | ||
|
|
b3e299b931 | ||
|
|
818e895af1 | ||
|
|
7e65f4f6ea | ||
|
|
8fac7a9f6c | ||
|
|
f25e5e3860 | ||
|
|
1cc96cd334 | ||
|
|
4e26527447 | ||
|
|
c214aa5149 | ||
|
|
48f8f3f5cf | ||
|
|
0b09e4bfcb | ||
|
|
4eab52ee75 | ||
|
|
b8e4f41987 | ||
|
|
f7553d73a2 | ||
|
|
b0e767eaf1 | ||
|
|
82ef687730 | ||
|
|
7e6ba94241 | ||
|
|
46a41f48ca | ||
|
|
86a8f4c5c7 | ||
|
|
afbb3ec37a | ||
|
|
d0ef37a487 | ||
|
|
611e5ab421 | ||
|
|
38729133e2 | ||
|
|
ce0b221573 | ||
|
|
95b61a5e12 | ||
|
|
3bbb748a08 | ||
|
|
9a843548c0 | ||
|
|
220a13b87f | ||
|
|
4b8301d39e | ||
|
|
0854a84eb9 | ||
|
|
ce91f1c0e6 | ||
|
|
060dbe1b56 | ||
|
|
b9d4a9c9f9 | ||
|
|
325e784ccd | ||
|
|
0d577584c3 | ||
|
|
27bc654b5b | ||
|
|
c1e3cfe7a7 | ||
|
|
96099807e1 | ||
|
|
b639a25856 | ||
|
|
0e6c83e521 | ||
|
|
987232a0a6 | ||
|
|
b54710950f | ||
|
|
d061e1065e | ||
|
|
0590f2975e | ||
|
|
5471c65c9a | ||
|
|
e299583eee | ||
|
|
8ac8e2e734 | ||
|
|
5b940f255f | ||
|
|
c05e9b118c | ||
|
|
45dc76de26 | ||
|
|
0dfe39ac87 | ||
|
|
27480d8e8e | ||
|
|
176bde269f | ||
|
|
df2cc09362 | ||
|
|
042cb1604a | ||
|
|
0acf3e0e30 | ||
|
|
4ad7e8f459 | ||
|
|
d445e0c877 | ||
|
|
e64ac4c418 | ||
|
|
94e19e1ac6 | ||
|
|
a254f38a23 | ||
|
|
52e0ce8b06 | ||
|
|
b039d960f5 | ||
|
|
66df043c19 | ||
|
|
8fbdb4b9ac | ||
|
|
0deaf6c50c | ||
|
|
3dce6d9f6a | ||
|
|
9aa59c7f62 | ||
|
|
7ba7f43199 | ||
|
|
c31c2d10b9 | ||
|
|
5a8f24eb46 | ||
|
|
59763ceecb | ||
|
|
282f4d6a89 | ||
|
|
6cdedf6049 | ||
|
|
61aa71ed34 | ||
|
|
901a825b61 | ||
|
|
75f35bcfe7 | ||
|
|
406b6148f5 | ||
|
|
f7b41625e5 | ||
|
|
0168fddae5 | ||
|
|
ef780d5034 | ||
|
|
6862184956 | ||
|
|
2b181b40f7 | ||
|
|
4c457c82ef | ||
|
|
3f8a519980 | ||
|
|
fb03fc073a | ||
|
|
2b93643277 | ||
|
|
396f1e92ca | ||
|
|
c60b6bdb38 | ||
|
|
9c83ddc122 | ||
|
|
b6b9036821 | ||
|
|
dc0b62f636 | ||
|
|
9102429a13 | ||
|
|
1fcb7afd3a | ||
|
|
fe14c64e5e | ||
|
|
107ca92458 | ||
|
|
9a8ccbaef2 | ||
|
|
d0347bb98f | ||
|
|
3fcb79bc1e | ||
|
|
41da1d6403 | ||
|
|
41baba9ed3 | ||
|
|
2f86cd8602 | ||
|
|
a1061c7145 | ||
|
|
2a0a0287d4 |
28
.gitignore
vendored
28
.gitignore
vendored
@@ -1,32 +1,18 @@
|
|||||||
avatar/*
|
avatar/
|
||||||
background/*
|
files/
|
||||||
files/*
|
file/
|
||||||
file/*
|
local/
|
||||||
local/*
|
logs/
|
||||||
_darcs/*
|
log/
|
||||||
logs/*
|
run/
|
||||||
log/*
|
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
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."
|
||||||
806
CONFIGURE
806
CONFIGURE
@@ -1,806 +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'.
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
background
|
|
||||||
----------
|
|
||||||
|
|
||||||
Users can upload backgrounds for their pages; this section defines
|
|
||||||
their use.
|
|
||||||
|
|
||||||
server: the server to use for background. Using a separate (even
|
|
||||||
virtual) server for this can speed up load times. Default is
|
|
||||||
null; same as site server.
|
|
||||||
dir: directory to write backgrounds too. Default is '/background/'
|
|
||||||
subdir of install dir.
|
|
||||||
path: path to backgrounds. Default is sub-path of install path; note
|
|
||||||
that you may need to change this if you change site-path too.
|
|
||||||
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.
|
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
design
|
|
||||||
------
|
|
||||||
|
|
||||||
Default design (colors and background) for the site. Actual appearance
|
|
||||||
depends on the theme. Null values mean to use the theme defaults.
|
|
||||||
|
|
||||||
backgroundcolor: Hex color of the site background.
|
|
||||||
contentcolor: Hex color of the content area background.
|
|
||||||
sidebarcolor: Hex color of the sidebar background.
|
|
||||||
textcolor: Hex color of all non-link text.
|
|
||||||
linkcolor: Hex color of all links.
|
|
||||||
backgroundimage: Image to use for the background.
|
|
||||||
disposition: Flags for whether or not to tile the background image.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
112
CONTRIBUTING.md
Normal file
112
CONTRIBUTING.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. Ensure you strip any trailing spaces off and checked the file with php-cs-fixer
|
||||||
|
2. Increase the version numbers in any examples files and the README.md to the new version that this
|
||||||
|
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
|
||||||
|
3. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
|
||||||
|
do not have permission to do that, you may request the second reviewer to merge it for you.
|
||||||
|
|
||||||
|
|
||||||
|
## Coding Standards
|
||||||
|
|
||||||
|
Since we will be expected to maintain your code once it's submitted, we ask you
|
||||||
|
to adhere to certain coding standards that make it easier for us to do so. If
|
||||||
|
code doesn't follow them, it will be rejected, so please read up on these.
|
||||||
|
|
||||||
|
|
||||||
|
## Bug Reports
|
||||||
|
|
||||||
|
Please report bugs to the issue tracker at
|
||||||
|
<https://notabug.org/diogo/gnu-social/issues> Avoid assigning the labels
|
||||||
|
yourself, as these are for the development team to assign priority and area of
|
||||||
|
coverage to a subject. Please only submit something here if you are certain it
|
||||||
|
is a bug or represents a feature enhancement that we do not presently have. If
|
||||||
|
you are uncertain whether it's a bug, please feel free to ask
|
||||||
|
at #social IRC channel on freenode.net https://www.freenode.net/.
|
||||||
|
|
||||||
|
When reporting a bug, please try to include as much information as possible,
|
||||||
|
including the environment being run on (if it's a common LAMP stack just give
|
||||||
|
us version numbers of the main stack components, that's fine), and the specific
|
||||||
|
error you get. If you do not get a client-facing error, please check the PHP
|
||||||
|
error_log and ensure there isn't something silently reported there, as well as
|
||||||
|
the GNU social log. Try to include steps to reproduce the error as well, as if
|
||||||
|
we cannot reproduce the error, we can't fix it!
|
||||||
|
|
||||||
|
It is perfectly acceptable to reference the archive page of a discussion on the
|
||||||
|
mailing list for the bug report, by the way, as long as it includes all the
|
||||||
|
information we need for a bug report.
|
||||||
|
|
||||||
|
|
||||||
|
## Submitting Feature Requests / Enhancement Requests
|
||||||
|
|
||||||
|
Social media is constantly evolving, and we welcome ideas about how we can
|
||||||
|
change and evolve GNU social to keep it the excellent piece of software that it
|
||||||
|
is. However, there are a few things we ask you do when submitting feature
|
||||||
|
requests:
|
||||||
|
|
||||||
|
1. Understand that since we have a limited amount of developers and these people
|
||||||
|
contribute in their free time, we may prioritize things differently than you
|
||||||
|
value them. Oftentimes this is because certain requests involve less changes
|
||||||
|
to the existing codebase than others, and therefore this makes them easier
|
||||||
|
to add.
|
||||||
|
2. Please search the existing feature requests and enhancements to see if a
|
||||||
|
similar request exists. If one does but you have different ideas about how
|
||||||
|
to do it or what it should entail, please add a comment to the existing idea
|
||||||
|
rather than create a new one for your "version" of it. Duplicate submissions
|
||||||
|
mean we spend more time maintaining the tracker and less time actually
|
||||||
|
working on the codebase!
|
||||||
|
3. When outlining the way that you see something working, don't be afraid to be
|
||||||
|
as detailed as possible! We may not implement it exactly as you describe for
|
||||||
|
any variety of reasons, but the more concrete and fleshed out an idea is, the
|
||||||
|
easier it is for us to know what you want and be able to implement it in a
|
||||||
|
sane and secure fashion.
|
||||||
|
4. When describing a possible new idea and its mechanisms of operation, the key
|
||||||
|
words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||||
|
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the issue submission
|
||||||
|
are to be interpreted as described in RFC 2119.
|
||||||
|
<https://tools.ietf.org/html/rfc2119>
|
||||||
|
|
||||||
|
Finally, and just as a call back to the first point, realize just because we
|
||||||
|
might not rush to implement something, doesn't mean that we don't want to
|
||||||
|
implement it! We would rather take the time to do something right the first
|
||||||
|
time, then hurriedly apply a new idea, or a fix, only to have to patch it later.
|
||||||
|
|
||||||
|
|
||||||
|
## Branch of Code Submissions
|
||||||
|
|
||||||
|
Unless you've been specifically directed otherwise, all submissions of code
|
||||||
|
should be against the `nightly` branch, so make sure any modifications are based
|
||||||
|
on Nightly.
|
||||||
|
|
||||||
|
|
||||||
|
## Copyright / Licensing
|
||||||
|
|
||||||
|
You acknowledge that by submitting code to GNU social, you are licensing it under
|
||||||
|
the GNU AGPLv3 unless there is an extenuating circumstance where it would be
|
||||||
|
licensed differently (such as modifications to an external library we include
|
||||||
|
such as Stomp).
|
||||||
|
|
||||||
|
You also acknowledge that unless you assign a copyright explicitly, it will be
|
||||||
|
assumed to be assigned to GNU social.
|
||||||
|
|
||||||
|
Thanks for considering submission, and happy hacking!
|
||||||
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 postActiv project. Following it isn't a gaurantee a patch will be accepted,
|
||||||
|
but it will help you avoid common problems.
|
||||||
|
|
||||||
|
1. Ensure all code control paths in all functions return a value.
|
||||||
|
|
||||||
|
2. Ensure all exceptions are trapped in an exception class, or minimally,
|
||||||
|
written to the log with common_log
|
||||||
|
|
||||||
|
3. Ensure the coding format standards are adhered to (see coding_standards.md)
|
||||||
|
|
||||||
|
4. Ensure that any new class that deals in public data has a corresponding new
|
||||||
|
API endpoint.
|
||||||
|
|
||||||
|
5. Ensure that all new API endpoints sanitize inputs and outputs properly.
|
||||||
|
|
||||||
|
6. Ensure that your version of the code works with PHP 7 on a standard
|
||||||
|
LAMP and LEMP stack (Linux+Apache+MariaDB+PHP and Linux+nginx+MariaDB+PHP)
|
||||||
|
|
||||||
|
7. If implementing new database functions, ensure they work with MariaDB
|
||||||
|
and postgreSQL.
|
||||||
|
|
||||||
|
8. Ensure all data that federates does so properly and has mechanisms to
|
||||||
|
catch and accomodate for federation transmission failure.
|
||||||
|
|
||||||
|
9. Ensure that nothing is left in an error state when it is avoidable.
|
||||||
|
|
||||||
|
10. Ensure that all code submitted is properly documented.
|
||||||
|
|
||||||
|
11. Ensure that there are no PHP Strict Standards or Parse errors in the code.
|
||||||
1498
DOCUMENTATION/DEVELOPERS/EVENTS.txt
Normal file
1498
DOCUMENTATION/DEVELOPERS/EVENTS.txt
Normal file
File diff suppressed because it is too large
Load Diff
355
DOCUMENTATION/DEVELOPERS/Plugins/README.md
Normal file
355
DOCUMENTATION/DEVELOPERS/Plugins/README.md
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
Plugin Development
|
||||||
|
=======================
|
||||||
|
|
||||||
|
SamplePlugin.php
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Each plugin requires a main class to interact with the GNU social system.
|
||||||
|
|
||||||
|
The main class usually extends the Plugin class that comes with GNU social.
|
||||||
|
|
||||||
|
The class has standard-named methods that will be called when certain events
|
||||||
|
happen in the code base. These methods have names like 'onX' where X is an
|
||||||
|
event name (see EVENTS.txt for the list of available events). Event handlers
|
||||||
|
have pre-defined arguments, based on which event they're handling. A typical
|
||||||
|
event handler:
|
||||||
|
|
||||||
|
```php
|
||||||
|
function onSomeEvent($paramA, &$paramB)
|
||||||
|
{
|
||||||
|
if ($paramA == 'jed') {
|
||||||
|
throw new Exception(sprintf(_m("Invalid parameter %s"), $paramA));
|
||||||
|
}
|
||||||
|
$paramB = 'spock';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Event Handlers
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Event handlers must return a Boolean value.
|
||||||
|
|
||||||
|
If they return false, all other event handlers for this event (in other plug-in)
|
||||||
|
will be skipped, and in some cases the default processing for that event would
|
||||||
|
be skipped. This is great for replacing the default action of an event.
|
||||||
|
|
||||||
|
If the handler returns true, processing of other event handlers and the default
|
||||||
|
processing will continue. This is great for extending existing functionality.
|
||||||
|
|
||||||
|
If the handler throws an exception, processing will stop, and the exception's
|
||||||
|
error will be shown to the user.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------------
|
||||||
|
|
||||||
|
To install a plugin (like this one), site admins add the following code to their
|
||||||
|
config.php file:
|
||||||
|
|
||||||
|
```php
|
||||||
|
addPlugin('Sample');
|
||||||
|
```
|
||||||
|
|
||||||
|
Plugins must be installed in one of the following directories:
|
||||||
|
|
||||||
|
* local/plugins/{$pluginclass}.php
|
||||||
|
* local/plugins/{$name}/{$pluginclass}.php
|
||||||
|
* local/{$pluginclass}.php
|
||||||
|
* local/{$name}/{$pluginclass}.php
|
||||||
|
* plugins/{$pluginclass}.php
|
||||||
|
* plugins/{$name}/{$pluginclass}.php
|
||||||
|
|
||||||
|
Here, `{$name}` is the name of the plugin, like 'Sample', and `{$pluginclass}`
|
||||||
|
is the name of the main class, like 'SamplePlugin'. Plugins that are part of
|
||||||
|
the main GNU social distribution go in 'plugins' and third-party or local ones
|
||||||
|
go in 'local'.
|
||||||
|
|
||||||
|
Simple plugins can be implemented as a single module. Others are more complex
|
||||||
|
and require additional modules; these should use their own directory, like
|
||||||
|
'local/plugins/{$name}/'. All files related to the plugin, including images,
|
||||||
|
JavaScript, CSS, external libraries or PHP modules should go in the plugin
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Plugin Configuration
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Plugins are configured using public instance attributes. To set their values,
|
||||||
|
site administrators use this syntax:
|
||||||
|
|
||||||
|
```php
|
||||||
|
addPlugin('Sample', ('attr1' => 'foo', 'attr2' => 'bar'));
|
||||||
|
```
|
||||||
|
|
||||||
|
The same plugin class can be initialized multiple times with different arguments:
|
||||||
|
|
||||||
|
```php
|
||||||
|
addPlugin('EmailNotify', array('sendTo' => 'evan@status.net'));
|
||||||
|
addPlugin('EmailNotify', array('sendTo' => 'brionv@status.net'));
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
class SamplePlugin extends Plugin
|
||||||
|
{
|
||||||
|
public $attr1 = null;
|
||||||
|
public $attr2 = null;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Initialization
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Plugins overload this method to do any initialization they need, like connecting
|
||||||
|
to remote servers or creating paths or so on. @return boolean hook value; true
|
||||||
|
means continue processing, false means stop.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function initialize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Clean Up
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Plugins overload this method to do any cleanup they need, like disconnecting from
|
||||||
|
remote servers or deleting temp files or so on.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function cleanup()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Database schema setup
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Plugins can add their own tables to the GNU social database. Plugins should use
|
||||||
|
GNU social's schema interface to add or delete tables. The ensureTable() method
|
||||||
|
provides an easy way to ensure a table's structure and availability.
|
||||||
|
|
||||||
|
By default, the schema is checked every time GNU social is run (say, when a Web
|
||||||
|
page is hit). Admins can configure their systems to only check the schema when
|
||||||
|
the checkschema.php script is run, greatly improving performance. However, they
|
||||||
|
need to remember to run that script after installing or upgrading a plugin!
|
||||||
|
|
||||||
|
```php
|
||||||
|
function onCheckSchema()
|
||||||
|
{
|
||||||
|
$schema = Schema::get();
|
||||||
|
|
||||||
|
// '''For storing user-submitted flags on profiles'''
|
||||||
|
|
||||||
|
$schema->ensureTable('user_greeting_count',
|
||||||
|
array(new ColumnDef('user_id', 'integer', null,
|
||||||
|
true, 'PRI'),
|
||||||
|
new ColumnDef('greeting_count', 'integer')));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Load related modules when needed
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Most non-trivial plugins will require extra modules to do their work. Typically
|
||||||
|
these include data classes, action classes, widget classes, or external libraries.
|
||||||
|
|
||||||
|
This method receives a class name and loads the PHP file related to that class.
|
||||||
|
By tradition, action classes typically have files named for the action, all
|
||||||
|
lower-case. Data classes are in files with the data class name, initial letter
|
||||||
|
capitalized.
|
||||||
|
|
||||||
|
Note that this method will be called for *all* overloaded classes, not just ones
|
||||||
|
in this plugin! So, make sure to return true by default to let other plugins,
|
||||||
|
and the core code, get a chance.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function onAutoload($cls)
|
||||||
|
{
|
||||||
|
$dir = dirname(__FILE__);
|
||||||
|
|
||||||
|
switch ($cls)
|
||||||
|
{
|
||||||
|
case 'HelloAction':
|
||||||
|
include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
|
||||||
|
return false;
|
||||||
|
case 'User_greeting_count':
|
||||||
|
include_once $dir . '/'.$cls.'.php';
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Map URLs to actions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
This event handler lets the plugin map URLs on the site to actions (and thus an
|
||||||
|
action handler class). Note that the action handler class for an action will be
|
||||||
|
named 'FoobarAction', where action = 'foobar'. The class must be loaded in the
|
||||||
|
onAutoload() method.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function onRouterInitialized($m)
|
||||||
|
{
|
||||||
|
$m->connect('main/hello',
|
||||||
|
array('action' => 'hello'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Modify the default menu to link to our custom action
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Using event handlers, it's possible to modify the default UI for pages almost
|
||||||
|
without limit. In this method, we add a menu item to the default primary menu
|
||||||
|
for the interface to link to our action.
|
||||||
|
|
||||||
|
Action Class
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The Action class provides a rich set of events to hook, as well as output methods.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function onEndPrimaryNav($action)
|
||||||
|
{
|
||||||
|
// '''common_local_url()''' gets the correct URL for the action name we provide
|
||||||
|
|
||||||
|
$action->menuItem(common_local_url('hello'),
|
||||||
|
_m('Hello'), _m('A warm greeting'), false, 'nav_hello');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPluginVersion(&$versions)
|
||||||
|
{
|
||||||
|
$versions[] = array('name' => 'Sample',
|
||||||
|
'version' => STATUSNET_VERSION,
|
||||||
|
'author' => 'Brion Vibber, Evan Prodromou',
|
||||||
|
'homepage' => 'http://example.org/plugin',
|
||||||
|
'rawdescription' =>
|
||||||
|
_m('A sample plugin to show basics of development for new hackers.'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
hello.php
|
||||||
|
------------------
|
||||||
|
|
||||||
|
This section is taken directly from the 'hello.php'. ( plugins/Sample/hello.php )
|
||||||
|
|
||||||
|
Give a warm greeting to our friendly user.
|
||||||
|
|
||||||
|
This sample action shows some basic ways of doing output in an action class.
|
||||||
|
|
||||||
|
Action classes have several output methods that they override from the parent class.
|
||||||
|
|
||||||
|
```php
|
||||||
|
class HelloAction extends Action
|
||||||
|
{
|
||||||
|
var $user = null;
|
||||||
|
var $gc = null;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Take arguments for running
|
||||||
|
------------------
|
||||||
|
|
||||||
|
This method is called first, and it lets the action class get all its arguments
|
||||||
|
and validate them. It's also the time to fetch any relevant data from the database.
|
||||||
|
|
||||||
|
Action classes should run parent::prepare(array $args = []) as the first line
|
||||||
|
of this method to make sure the default argument-processing happens.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function prepare(array $args = [])
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
$this->user = common_current_user();
|
||||||
|
|
||||||
|
if (!empty($this->user)) {
|
||||||
|
$this->gc = User_greeting_count::inc($this->user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Handle request
|
||||||
|
------------------
|
||||||
|
|
||||||
|
This is the main method for handling a request. Note that most preparation
|
||||||
|
should be done in the prepare() method; by the time handle() is called the
|
||||||
|
action should be more or less ready to go.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function handle()
|
||||||
|
{
|
||||||
|
parent::handle();
|
||||||
|
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Title of this page
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Override this method to show a custom title.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
if (empty($this->user)) {
|
||||||
|
return _m('Hello');
|
||||||
|
} else {
|
||||||
|
return sprintf(_m('Hello, %s'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Show content in the content area
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The default GNU social page has a lot of decorations: menus, logos, tabs, all
|
||||||
|
that jazz. This method is used to show content in the content area of the
|
||||||
|
page; it's the main thing you want to overload. This method also demonstrates
|
||||||
|
use of a plural localized string.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
if (empty($this->user)) {
|
||||||
|
$this->element('p', array('class' => 'greeting'),
|
||||||
|
_m('Hello, stranger!'));
|
||||||
|
} else {
|
||||||
|
$this->element('p', array('class' => 'greeting'),
|
||||||
|
sprintf(_m('Hello, %s'), $this->user->nickname));
|
||||||
|
$this->element('p', array('class' => 'greeting_count'),
|
||||||
|
sprintf(_m('I have greeted you %d time.',
|
||||||
|
'I have greeted you %d times.',
|
||||||
|
$this->gc->greeting_count),
|
||||||
|
$this->gc->greeting_count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Return true if read only.
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Some actions only read from the database; others read and write. The simple
|
||||||
|
database load-balancer built into GNU social will direct read-only actions to
|
||||||
|
database mirrors (if they are configured) and read-write actions to the master database.
|
||||||
|
|
||||||
|
This defaults to false to avoid data integrity issues, but you should make sure
|
||||||
|
to overload it for performance gains.
|
||||||
|
|
||||||
|
```php
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
957
DOCUMENTATION/SYSTEM_ADMINISTRATORS/CONFIGURE.md
Normal file
957
DOCUMENTATION/SYSTEM_ADMINISTRATORS/CONFIGURE.md
Normal file
@@ -0,0 +1,957 @@
|
|||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
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 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. 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).
|
||||||
|
|
||||||
|
* `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.
|
||||||
44
DOCUMENTATION/SYSTEM_ADMINISTRATORS/PLUGINS.md
Normal file
44
DOCUMENTATION/SYSTEM_ADMINISTRATORS/PLUGINS.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
Plugins
|
||||||
|
=======
|
||||||
|
|
||||||
|
GNU social supports a simple but
|
||||||
|
powerful plugin architecture. Important events in the code are named,
|
||||||
|
like 'StartNoticeSave', and other software can register interest
|
||||||
|
in those events. When the events happen, the other software is called
|
||||||
|
and has a choice of accepting or rejecting the events.
|
||||||
|
|
||||||
|
In the simplest case, you can add a function to config.php and use the
|
||||||
|
Event::addHandler() function to hook an event:
|
||||||
|
|
||||||
|
function AddMyWebsiteLink($action)
|
||||||
|
{
|
||||||
|
$action->menuItem('http://mywebsite.net/', _('My web site'), _('Example web link'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::addHandler('EndPrimaryNav', 'AddMyWebsiteLink');
|
||||||
|
|
||||||
|
This adds a menu item to the end of the main navigation menu. You can
|
||||||
|
see the list of existing events, and parameters that handlers must
|
||||||
|
implement, in EVENTS.txt.
|
||||||
|
|
||||||
|
The Plugin class in lib/plugin.php makes it easier to write more
|
||||||
|
complex plugins. Sub-classes can just create methods named
|
||||||
|
'onEventName', where 'EventName' is the name of the event (case
|
||||||
|
matters!). These methods will be automatically registered as event
|
||||||
|
handlers by the Plugin constructor (which you must call from your own
|
||||||
|
class's constructor).
|
||||||
|
|
||||||
|
Several example plugins are included in the plugins/ directory. You
|
||||||
|
can enable a plugin with the following line in config.php:
|
||||||
|
|
||||||
|
addPlugin('Example', array('param1' => 'value1',
|
||||||
|
'param2' => 'value2'));
|
||||||
|
|
||||||
|
This will look for and load files named 'ExamplePlugin.php' or
|
||||||
|
'Example/ExamplePlugin.php' either in the plugins/ directory (for
|
||||||
|
plugins that ship with GNU social) or in the local/ directory (for
|
||||||
|
plugins you write yourself or that you get from somewhere else) or
|
||||||
|
local/plugins/.
|
||||||
|
|
||||||
|
Plugins are documented in their own directories.
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
Initial simple way to Webfinger enable your domain -- needs PHP.
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
This guide needs some updating, since it will only guide you to present
|
||||||
|
XML data (while the curl command likely gives you JSON). The workaround
|
||||||
|
is to simply make curl get 'webfinger.xml' instead, and/or have another
|
||||||
|
file that contains JSON, but that requires editing the PHP file as well.
|
||||||
|
|
||||||
|
Step 1
|
||||||
|
======
|
||||||
|
|
||||||
|
Put the 'dot-well-known' on your website, so it loads at:
|
||||||
|
|
||||||
|
https://example.com/.well-known/
|
||||||
|
|
||||||
|
(Remember the . at the beginning of this one, which is common practice
|
||||||
|
for "hidden" files and why we have renamed it "dot-")
|
||||||
|
|
||||||
|
Step 2
|
||||||
|
======
|
||||||
|
|
||||||
|
Edit the .well-known/host-meta file and replace "example.com" with the
|
||||||
|
domain name you're hosting the .well-known directory on.
|
||||||
|
|
||||||
|
Using vim you can do this as a quick method:
|
||||||
|
$ vim .well-known/host-meta [ENTER]
|
||||||
|
:%s/example.com/domain.com/ [ENTER]
|
||||||
|
:wq [ENTER]
|
||||||
|
|
||||||
|
Step 3
|
||||||
|
======
|
||||||
|
|
||||||
|
For each user on your site, and this might only be you...
|
||||||
|
|
||||||
|
In the webfinger directory, make a copy of the example@example.com.xml file
|
||||||
|
so that it's called (replace username and example.com with appropriate
|
||||||
|
values, the domain name should be the same as you're "socialifying"):
|
||||||
|
|
||||||
|
username@example.com.xml
|
||||||
|
|
||||||
|
Then edit the file contents, replacing "social.example.com" with your
|
||||||
|
GNU social instance's base path, and change the user ID number (and
|
||||||
|
nickname for the FOAF link) to that of your account on your social
|
||||||
|
site. If you don't know your user ID number, you can see this on your
|
||||||
|
GNU social profile page by looking at the destination URLs in the
|
||||||
|
Feeds links.
|
||||||
|
|
||||||
|
PROTIP: You can get the bulk of the contents (note the <Subject> element though)
|
||||||
|
from curling down your real webfinger data:
|
||||||
|
$ curl https://social.example.com/.well-known/webfinger?resource=acct:username@social.example.com
|
||||||
|
|
||||||
|
Finally
|
||||||
|
=======
|
||||||
|
|
||||||
|
Using this method, though fiddly, you can now be @user@domain without
|
||||||
|
the need for any prefixes for subdomains, etc.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:hm="http://host-meta.net/xrd/1.0">
|
||||||
|
<Link rel="lrdd" type="application/xrd+xml"
|
||||||
|
template="https://example.com/.well-known/webfinger?resource={uri}"/>
|
||||||
|
</XRD>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||||
|
<Subject>acct:username@example.com</Subject>
|
||||||
|
<Alias>acct:username@social.example.com</Alias>
|
||||||
|
<Alias>https://social.example.com/user/1</Alias>
|
||||||
|
<Link rel="http://webfinger.net/rel/profile-page"
|
||||||
|
type="text/html"
|
||||||
|
href="https://social.example.com/user/1"/>
|
||||||
|
|
||||||
|
<Link rel="http://schemas.google.com/g/2010#updates-from"
|
||||||
|
type="application/atom+xml"
|
||||||
|
href="https://social.example.com/api/statuses/user_timeline/1.atom"/>
|
||||||
|
|
||||||
|
<!-- Is this/was this ever supported?
|
||||||
|
<Link rel="http://microformats.org/profile/hcard"
|
||||||
|
type="text/html"
|
||||||
|
href="https://social.example.com/hcard"/> -->
|
||||||
|
|
||||||
|
<Link rel="http://gmpg.org/xfn/11"
|
||||||
|
type="text/html"
|
||||||
|
href="https://social.example.com/user/1"/>
|
||||||
|
|
||||||
|
<Link rel="describedby"
|
||||||
|
type="application/rdf+xml"
|
||||||
|
href="https://social.example.com/username/foaf"/>
|
||||||
|
|
||||||
|
<Link rel="http://salmon-protocol.org/ns/salmon-replies"
|
||||||
|
href="https://social.example.com/main/salmon/user/1"/>
|
||||||
|
|
||||||
|
<Link rel="http://salmon-protocol.org/ns/salmon-mention"
|
||||||
|
href="https://social.example.com/main/salmon/user/1"/>
|
||||||
|
|
||||||
|
<Link rel="http://ostatus.org/schema/1.0/subscribe"
|
||||||
|
template="https://social.example.com/main/ostatussub?profile={uri}"/>
|
||||||
|
</XRD>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GNU social
|
||||||
|
* Copyright (C) 2010, Free Software Foundation, Inc
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// basename should make sure we can't escape this directory
|
||||||
|
$u = basename($_GET['resource']);
|
||||||
|
|
||||||
|
if (!strpos($u, '@')) {
|
||||||
|
throw new Exception('Bad resource');
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mb_strpos($u, 'acct:')===0) {
|
||||||
|
$u = substr($u, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just to be a little bit safer, you know, with all the unicode stuff going on
|
||||||
|
$u = filter_var($u, FILTER_SANITIZE_EMAIL);
|
||||||
|
|
||||||
|
$f = $u . ".xml";
|
||||||
|
|
||||||
|
if (file_exists($f)) {
|
||||||
|
header('Content-Disposition: attachment; filename="'.urlencode($f).'"');
|
||||||
|
header('Content-type: application/xrd+xml');
|
||||||
|
echo file_get_contents($f);
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
Upgrading
|
||||||
|
=========
|
||||||
|
|
||||||
|
GNU social 1.1.x to GNU social 1.2.x
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
If you are tracking the GNU social git repository, we currently recommend
|
||||||
|
using the "master" branch (or nightly if you want to use latest features)
|
||||||
|
and follow this procedure:
|
||||||
|
|
||||||
|
0. Backup your data. The StatusNet upgrade discussions below have some
|
||||||
|
guidelines to back up the database and files (mysqldump and rsync).
|
||||||
|
|
||||||
|
MAKE SURE YOU ARE THE SAME USER THAT RUNS THE PHP FILES WHILE PERFORMING
|
||||||
|
THE COMMANDS BELOW (I usually prepend the commands with 'sudo -u social')
|
||||||
|
|
||||||
|
1. Stop your queue daemons (you can run this command even if you do not
|
||||||
|
use the queue daemons):
|
||||||
|
$ bash scripts/stopdaemons.sh
|
||||||
|
|
||||||
|
2. Run the command to fetch the latest sourcecode:
|
||||||
|
$ git pull
|
||||||
|
|
||||||
|
If you are not using git we recommend following the instructions below
|
||||||
|
for upgrading "StatusNet 1.1.x to GNU social 1.2.x" as they are similar.
|
||||||
|
|
||||||
|
3. Run the upgrade script:
|
||||||
|
$ php scripts/upgrade.php
|
||||||
|
|
||||||
|
The upgrade script will likely take a long time because it will
|
||||||
|
upgrade the tables to another character encoding and make other
|
||||||
|
automated upgrades. Make sure it ends without errors. If you get
|
||||||
|
errors, create a new task on https://git.gnu.io/gnu/gnu-social/issues
|
||||||
|
|
||||||
|
4. Start your queue daemons again (you can run this command even if you
|
||||||
|
do not use the queue daemons):
|
||||||
|
$ bash scripts/startdaemons.sh
|
||||||
|
|
||||||
|
5. Report any issues at https://git.gnu.io/gnu/gnu-social/issues
|
||||||
|
|
||||||
|
If you are using ssh keys to log in to your server, you can make this
|
||||||
|
procedure pretty painless (assuming you have automated backups already).
|
||||||
|
Make sure you "cd" into the correct directory (in this case "htdocs")
|
||||||
|
and use the correct login@hostname combo:
|
||||||
|
$ ssh social@domain.example 'cd htdocs
|
||||||
|
&& bash scripts/stopdaemons.sh
|
||||||
|
&& git pull
|
||||||
|
&& time php scripts/upgrade.php
|
||||||
|
&& bash scripts/startdaemons.sh'
|
||||||
|
|
||||||
|
StatusNet 1.1.x to GNU social 1.2.x
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
We cannot support migrating from any other version of StatusNet than
|
||||||
|
1.1.1. If you are running a StatusNet version lower than this, please
|
||||||
|
follow the upgrade procedures for each respective StatusNet version.
|
||||||
|
|
||||||
|
You are now running StatusNet 1.1.1 and want to migrate to GNU social
|
||||||
|
1.2.x. Beware there may be changes in minimum required version of PHP
|
||||||
|
and the modules required, so review the INSTALL file (php5-intl is a
|
||||||
|
newly added dependency for example).
|
||||||
|
|
||||||
|
* Before you begin: Make backups. Always make backups. Of your entire
|
||||||
|
directory structure and the database too. All tables. All data. Alles.
|
||||||
|
|
||||||
|
0. Make a backup of everything. To backup the database, you can use a
|
||||||
|
variant of this command (you will be prompted for the database password):
|
||||||
|
$ mysqldump -u dbuser -p dbname > social-backup.sql
|
||||||
|
|
||||||
|
1. Stop your queue daemons 'bash scripts/stopdaemons.sh' should do it.
|
||||||
|
Not everyone runs queue daemons, but the above command won't hurt.
|
||||||
|
|
||||||
|
2. Unpack your GNU social code to a fresh directory. You can do this
|
||||||
|
by cloning our git repository:
|
||||||
|
$ git clone https://git.gnu.io/gnu/gnu-social.git gnusocial
|
||||||
|
|
||||||
|
3. Synchronize your local files to the GNU social directory. These
|
||||||
|
will be the local files such as avatars, config and files:
|
||||||
|
|
||||||
|
avatar/*
|
||||||
|
file/*
|
||||||
|
local/*
|
||||||
|
.htaccess
|
||||||
|
config.php
|
||||||
|
|
||||||
|
This command will point you in the right direction on how to do it:
|
||||||
|
$ rsync -avP statusnet/{.htaccess,avatar,file,local,config.php} gnusocial/
|
||||||
|
|
||||||
|
4. Replace your old StatusNet directory with the new GNU social
|
||||||
|
directory in your webserver root.
|
||||||
|
|
||||||
|
5. Run the upgrade script: 'php scripts/upgrade.php'
|
||||||
|
The upgrade script will likely take a long time because it will
|
||||||
|
upgrade the tables to another character encoding and make other
|
||||||
|
automated upgrades. Make sure it ends without errors. If you get
|
||||||
|
errors, create a new task on https://git.gnu.io/gnu/gnu-social/issues
|
||||||
|
|
||||||
|
6. Start your queue daemons: 'bash scripts/startdaemons.sh'
|
||||||
|
|
||||||
|
7. Report any issues at https://git.gnu.io/gnu/gnu-social/issues
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
### GNU social "fancy URL" setup
|
||||||
|
#
|
||||||
|
# Change the "RewriteBase" in the new .htaccess file to be the URL path
|
||||||
|
# to your GNU Social installation on your server. Typically this will
|
||||||
|
# be the path to your GNU Social directory relative to your Web root.
|
||||||
|
# If you are installing it in the root directory, leave it as '/'.
|
||||||
|
#
|
||||||
|
# If it doesn't work, double-check that AllowOverride for the GNU Social
|
||||||
|
# directory is 'All' in your Apache configuration file. This can be
|
||||||
|
# * /etc/apache2/apache2.conf (generic)
|
||||||
|
# * /etc/apache2/sites-available/default(on Debian and Ubuntu)
|
||||||
|
# * ...many other variations depending on distribution...
|
||||||
|
#
|
||||||
|
# See the Apache documentation for .htaccess files for more details:
|
||||||
|
# https://httpd.apache.org/docs/2.4/howto/htaccess.html
|
||||||
|
#
|
||||||
|
# Also, check that mod_rewrite is installed and enabled:
|
||||||
|
# https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html
|
||||||
|
|
||||||
|
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
|
||||||
|
# NOTE: change this to your actual GNU social base URL path,
|
||||||
|
# minus the domain part:
|
||||||
|
#
|
||||||
|
# https://social.example.com/ => /
|
||||||
|
# https://example.com/social/ => /social/
|
||||||
|
#
|
||||||
|
RewriteBase /
|
||||||
|
#RewriteBase /mublog/
|
||||||
|
|
||||||
|
## Uncomment these if having trouble with API authentication
|
||||||
|
## when PHP is running in CGI or FastCGI mode.
|
||||||
|
#
|
||||||
|
#RewriteCond %{HTTP:Authorization} ^(.*)
|
||||||
|
#RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]
|
||||||
|
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule (.*) index.php?p=$1 [L,QSA]
|
||||||
|
|
||||||
|
## You can also use PATHINFO by using this RewriteRule instead:
|
||||||
|
# RewriteRule (.*) index.php/$1 [L,QSA]
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<FilesMatch "\.(ini)">
|
||||||
|
<IfVersion < 2.3>
|
||||||
|
Order allow,deny
|
||||||
|
Deny from all
|
||||||
|
</IfVersion>
|
||||||
|
<IfVersion >= 2.3>
|
||||||
|
Require all denied
|
||||||
|
</IfVersion>
|
||||||
|
</FilesMatch>
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
server {
|
||||||
|
listen [::]:80;
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
# FIXME: Change domain name here (and also make sure you do the same in the next 'server' section)
|
||||||
|
server_name social.example.org;
|
||||||
|
|
||||||
|
# redirect all traffic to HTTPS
|
||||||
|
rewrite ^ https://$host$request_uri? permanent;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
# HTTPS is mandatory on GNU social unless you are using Tor network. Seriously.
|
||||||
|
# Set it up with a cert (any cert) before you run the install.
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
listen 443 ssl http2;
|
||||||
|
|
||||||
|
# Root
|
||||||
|
# FIXME: Change the path below to where you installed GNU social
|
||||||
|
root /path/to/gnusocial/root;
|
||||||
|
|
||||||
|
# Server name
|
||||||
|
# FIXME: Change "social.example.org" to your site's domain name
|
||||||
|
server_name social.example.org;
|
||||||
|
|
||||||
|
# SSL
|
||||||
|
# FIXME: Change the paths to setup your SSL key/cert. See https://cipherli.st/ for more information
|
||||||
|
ssl_certificate ssl/certs/social.example.org.crt;
|
||||||
|
ssl_certificate_key ssl/private/social.example.org.key;
|
||||||
|
|
||||||
|
# Index
|
||||||
|
index index.php;
|
||||||
|
|
||||||
|
# PHP
|
||||||
|
location ~ ^/(index|install)\.php$ {
|
||||||
|
#location ^~ /index.php {
|
||||||
|
include fastcgi_params;
|
||||||
|
include snippets/fastcgi-php.conf;
|
||||||
|
|
||||||
|
fastcgi_pass unix:/run/php/php-fpm.sock;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Don't allow any PHP file other than index.php to be executed
|
||||||
|
# This will ensure that nor config.php nor plugin files with eventual hardcoded security information are downloadable
|
||||||
|
# And this is better than allowing php files to be executed in case of forgotten `if (!defined('GNUSOCIAL')) { exit(1); }`
|
||||||
|
location ~ \.php$ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Location
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ @index_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fancy URLs
|
||||||
|
error_page 404 @index_handler;
|
||||||
|
location @index_handler {
|
||||||
|
rewrite ^(.*)$ /index.php?p=$1 last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Restrict access that is unnecessary anyway
|
||||||
|
location ~ /\.(ht|git) {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Hardening (optional)
|
||||||
|
#
|
||||||
|
# add_header Strict-Transport-Security "max-age=15768000; preload;";
|
||||||
|
# add_header X-Content-Type-Options nosniff;
|
||||||
|
# add_header Referrer-Policy strict-origin-when-cross-origin;
|
||||||
|
# add_header Content-Security-Policy "default-src 'self' 'unsafe-inline'; frame-ancestors 'self'; form-action 'self'; style-src 'self' 'unsafe-inline'; img-src * blob: data:;";
|
||||||
|
# add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
# add_header X-Robots-Tag all; # Not really hardening, just here for strictness purposes
|
||||||
|
#
|
||||||
|
# client_max_body_size 15M;
|
||||||
|
# client_body_buffer_size 128k;
|
||||||
|
# gzip_vary on;
|
||||||
|
#
|
||||||
|
# location ~* \.(?:css|js|woff|svg|gif|png|webp|ttf|ico|jpe?g)$ {
|
||||||
|
# gzip on;
|
||||||
|
# gzip_comp_level 4;
|
||||||
|
# add_header Cache-Control "public";
|
||||||
|
# expires 30d;
|
||||||
|
# access_log off;
|
||||||
|
# log_not_found off;
|
||||||
|
# }
|
||||||
|
}
|
||||||
1465
EVENTS.txt
1465
EVENTS.txt
File diff suppressed because it is too large
Load Diff
468
INSTALL
468
INSTALL
@@ -1,468 +0,0 @@
|
|||||||
TABLE OF CONTENTS
|
|
||||||
=================
|
|
||||||
* Prerequisites
|
|
||||||
- PHP modules
|
|
||||||
- Better performance
|
|
||||||
* Installation
|
|
||||||
- Getting it up and running
|
|
||||||
- Fancy URLs
|
|
||||||
- Sphinx
|
|
||||||
- SMS
|
|
||||||
- Queues and daemons
|
|
||||||
- Themes
|
|
||||||
- Translation
|
|
||||||
- Backups
|
|
||||||
- Private
|
|
||||||
|
|
||||||
Prerequisites
|
|
||||||
=============
|
|
||||||
|
|
||||||
PHP modules
|
|
||||||
-----------
|
|
||||||
|
|
||||||
The following software packages are *required* for this software to
|
|
||||||
run correctly.
|
|
||||||
|
|
||||||
- PHP 5.4+ For newer versions, some functions that are used may be
|
|
||||||
disabled by default, such as the pcntl_* family. See the
|
|
||||||
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
|
|
||||||
recommended and also some variant of 'suexec' (or a
|
|
||||||
proper setup php-fpm pool)
|
|
||||||
NOTE: mod_rewrite or its equivalent is extremely useful.
|
|
||||||
|
|
||||||
Your PHP installation must include the following PHP extensions for a
|
|
||||||
functional setup of GNU Social:
|
|
||||||
|
|
||||||
- openssl (compiled in for Debian, enabled manually in Arch Linux)
|
|
||||||
- php5-curl Fetching files by HTTP.
|
|
||||||
- php5-gd Image manipulation (scaling).
|
|
||||||
- php5-gmp For Salmon signatures (part of OStatus).
|
|
||||||
- php5-json For WebFinger lookups and more.
|
|
||||||
- php5-mysqlnd The native driver for PHP5 MariaDB connections. If you
|
|
||||||
use MySQL, 'mysql' or 'mysqli' may work.
|
|
||||||
|
|
||||||
The above package names are for Debian based systems. In the case of
|
|
||||||
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
|
|
||||||
------------------
|
|
||||||
|
|
||||||
For some functionality, you will also need the following extensions:
|
|
||||||
|
|
||||||
- opcache Improves performance a _lot_. Included in PHP, must be
|
|
||||||
enabled manually in php.ini for most distributions. Find
|
|
||||||
and set at least: opcache.enable=1
|
|
||||||
- mailparse Efficient parsing of email requires this extension.
|
|
||||||
Submission by email or SMS-over-email uses this.
|
|
||||||
- sphinx A client for the sphinx server, an alternative to MySQL
|
|
||||||
or Postgresql fulltext search. You will also need a
|
|
||||||
Sphinx server to serve the search queries.
|
|
||||||
- gettext For multiple languages. Default on many PHP installs;
|
|
||||||
will be emulated if not present.
|
|
||||||
- exif For thumbnails to be properly oriented.
|
|
||||||
|
|
||||||
You may also experience better performance from your site if you configure
|
|
||||||
a PHP cache/accelerator. Most distributions come with "opcache" support.
|
|
||||||
Enable it in your php.ini, it is documented there together with its settings.
|
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
Getting it up and running
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
Installing the basic GNU Social web component is relatively easy,
|
|
||||||
especially if you've previously installed PHP/MariaDB packages.
|
|
||||||
|
|
||||||
1. Unpack the tarball you downloaded on your Web server. Usually a
|
|
||||||
command like this will work:
|
|
||||||
|
|
||||||
tar zxf gnusocial-*.tar.gz
|
|
||||||
|
|
||||||
...which will make a gnusocial-x.y.z subdirectory in your current
|
|
||||||
directory. (If you don't have shell access on your Web server, you
|
|
||||||
may have to unpack the tarball on your local computer and FTP the
|
|
||||||
files to the server.)
|
|
||||||
|
|
||||||
2. Move the tarball to a directory of your choosing in your Web root
|
|
||||||
directory. Usually something like this will work:
|
|
||||||
|
|
||||||
mv gnusocial-x.y.z /var/www/gnusocial
|
|
||||||
|
|
||||||
This will often make your GNU Social instance available in the gnusocial
|
|
||||||
path of your server, like "http://example.net/gnusocial". "social" or
|
|
||||||
"blog" might also be good path names. If you know how to configure
|
|
||||||
virtual hosts on your web server, you can try setting up
|
|
||||||
"http://social.example.net/" or the like.
|
|
||||||
|
|
||||||
If you have "rewrite" support on your webserver, and you should,
|
|
||||||
then please enable this in order to make full use of your site. This
|
|
||||||
will enable "Fancy URL" support, which you can read more about if you
|
|
||||||
scroll down a bit in this document.
|
|
||||||
|
|
||||||
3. Make your target directory writeable by the Web server.
|
|
||||||
|
|
||||||
chmod a+w /var/www/gnusocial/
|
|
||||||
|
|
||||||
On some systems, this will probably work:
|
|
||||||
|
|
||||||
chgrp www-data /var/www/gnusocial/
|
|
||||||
chmod g+w /var/www/gnusocial/
|
|
||||||
|
|
||||||
If your Web server runs as another user besides "www-data", try
|
|
||||||
that user's default group instead. As a last resort, you can create
|
|
||||||
a new group like "gnusocial" and add the Web server's user to the group.
|
|
||||||
|
|
||||||
4. You should also take this moment to make your avatar, background, and
|
|
||||||
file subdirectories writeable by the Web server. An insecure way to do
|
|
||||||
this is:
|
|
||||||
|
|
||||||
chmod a+w /var/www/gnusocial/avatar
|
|
||||||
chmod a+w /var/www/gnusocial/background
|
|
||||||
chmod a+w /var/www/gnusocial/file
|
|
||||||
|
|
||||||
You can also make the avatar, background, and file directories
|
|
||||||
writeable by the Web server group, as noted above.
|
|
||||||
|
|
||||||
5. Create a database to hold your site data. Something like this
|
|
||||||
should work:
|
|
||||||
|
|
||||||
mysqladmin -u "root" --password="rootpassword" create gnusocial
|
|
||||||
|
|
||||||
Note that GNU Social should have its own database; you should not share
|
|
||||||
the database with another program. You can name it whatever you want,
|
|
||||||
though.
|
|
||||||
|
|
||||||
(If you don't have shell access to your server, you may need to use
|
|
||||||
a tool like phpMyAdmin to create a database. Check your hosting
|
|
||||||
service's documentation for how to create a new MariaDB database.)
|
|
||||||
|
|
||||||
6. Create a new database account that GNU Social will use to access the
|
|
||||||
database. If you have shell access, this will probably work from the
|
|
||||||
MariaDB shell:
|
|
||||||
|
|
||||||
GRANT ALL on gnusocial.*
|
|
||||||
TO 'gnusocial'@'localhost'
|
|
||||||
IDENTIFIED BY 'agoodpassword';
|
|
||||||
|
|
||||||
You should change the user identifier 'gnusocial' and 'agoodpassword'
|
|
||||||
to your preferred new database username and password. You may want to
|
|
||||||
test logging in to MariaDB as this new user.
|
|
||||||
|
|
||||||
7. In a browser, navigate to the GNU Social install script; something like:
|
|
||||||
|
|
||||||
http://social.example.net/install.php
|
|
||||||
|
|
||||||
Enter the database connection information and your site name. The
|
|
||||||
install program will configure your site and install the initial,
|
|
||||||
almost-empty database.
|
|
||||||
|
|
||||||
8. You should now be able to navigate to your social site's main directory
|
|
||||||
and see the "Public Timeline", which will probably be empty. You can
|
|
||||||
now register new user, post some notices, edit your profile, etc.
|
|
||||||
|
|
||||||
Fancy URLs
|
|
||||||
----------
|
|
||||||
|
|
||||||
By default, GNU Social will use URLs that include the main PHP program's
|
|
||||||
name in them. For example, a user's home profile might be found at:
|
|
||||||
|
|
||||||
http://example.net/gnusocial/index.php/gnusocial/fred
|
|
||||||
|
|
||||||
On certain systems that don't support this kind of syntax, they'll
|
|
||||||
look like this:
|
|
||||||
|
|
||||||
http://example.net/gnusocial/index.php?p=gnusocial/fred
|
|
||||||
|
|
||||||
It's possible to configure the software so it looks like this instead:
|
|
||||||
|
|
||||||
http://example.net/gnusocial/fred
|
|
||||||
|
|
||||||
These "fancy URLs" are more readable and memorable for users. To use
|
|
||||||
fancy URLs, you must either have Apache 2.x with .htaccess enabled and
|
|
||||||
mod_rewrite enabled, -OR- know how to configure "url redirection" in
|
|
||||||
your server (like lighttpd or nginx).
|
|
||||||
|
|
||||||
1. Copy the htaccess.sample file to .htaccess in your StatusNet
|
|
||||||
directory.
|
|
||||||
|
|
||||||
2. Change the "RewriteBase" in the new .htaccess file to be the URL path
|
|
||||||
to your GNU Social installation on your server. Typically this will
|
|
||||||
be the path to your GNU Social directory relative to your Web root.
|
|
||||||
If you are installing it in the root directory, leave it as '/'.
|
|
||||||
|
|
||||||
3. Add, uncomment or change a line in your config.php file so it says:
|
|
||||||
|
|
||||||
$config['site']['fancy'] = true;
|
|
||||||
|
|
||||||
You should now be able to navigate to a "fancy" URL on your server,
|
|
||||||
like:
|
|
||||||
|
|
||||||
http://example.net/gnusocial/main/register
|
|
||||||
|
|
||||||
If you changed your HTTP server configuration, you may need to restart
|
|
||||||
the server first.
|
|
||||||
|
|
||||||
If it doesn't work, double-check that AllowOverride for the GNU Social
|
|
||||||
directory is 'All' in your Apache configuration file. This is usually
|
|
||||||
/etc/httpd.conf, /etc/apache/httpd.conf, or (on Debian and Ubuntu)
|
|
||||||
/etc/apache2/sites-available/default. See the Apache documentation for
|
|
||||||
.htaccess files for more details:
|
|
||||||
|
|
||||||
http://httpd.apache.org/docs/2.2/howto/htaccess.html
|
|
||||||
|
|
||||||
Also, check that mod_rewrite is installed and enabled:
|
|
||||||
|
|
||||||
http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html
|
|
||||||
|
|
||||||
Sphinx
|
|
||||||
------
|
|
||||||
|
|
||||||
To use a Sphinx server to search users and notices, you'll need to
|
|
||||||
enable the SphinxSearch plugin. Add to your config.php:
|
|
||||||
|
|
||||||
addPlugin('SphinxSearch');
|
|
||||||
$config['sphinx']['server'] = 'searchhost.local';
|
|
||||||
|
|
||||||
You also need to install, compile and enable the sphinx pecl extension for
|
|
||||||
php on the client side, which itself depends on the sphinx development files.
|
|
||||||
|
|
||||||
See plugins/SphinxSearch/README for more details and server setup.
|
|
||||||
|
|
||||||
SMS
|
|
||||||
---
|
|
||||||
|
|
||||||
StatusNet supports a cheap-and-dirty system for sending update messages
|
|
||||||
to mobile phones and for receiving updates from the mobile. Instead of
|
|
||||||
sending through the SMS network itself, which is costly and requires
|
|
||||||
buy-in from the wireless carriers, it simply piggybacks on the email
|
|
||||||
gateways that many carriers provide to their customers. So, SMS
|
|
||||||
configuration is essentially email configuration.
|
|
||||||
|
|
||||||
Each user sends to a made-up email address, which they keep a secret.
|
|
||||||
Incoming email that is "From" the user's SMS email address, and "To"
|
|
||||||
the users' secret email address on the site's domain, will be
|
|
||||||
converted to a notice and stored in the DB.
|
|
||||||
|
|
||||||
For this to work, there *must* be a domain or sub-domain for which all
|
|
||||||
(or most) incoming email can pass through the incoming mail filter.
|
|
||||||
|
|
||||||
1. Run the SQL script carrier.sql in your StatusNet database. This will
|
|
||||||
usually work:
|
|
||||||
|
|
||||||
mysql -u "statusnetuser" --password="statusnetpassword" statusnet < db/carrier.sql
|
|
||||||
|
|
||||||
This will populate your database with a list of wireless carriers
|
|
||||||
that support email SMS gateways.
|
|
||||||
|
|
||||||
2. Make sure the maildaemon.php file is executable:
|
|
||||||
|
|
||||||
chmod +x scripts/maildaemon.php
|
|
||||||
|
|
||||||
Note that "daemon" is kind of a misnomer here; the script is more
|
|
||||||
of a filter than a daemon.
|
|
||||||
|
|
||||||
2. Edit /etc/aliases on your mail server and add the following line:
|
|
||||||
|
|
||||||
*: /path/to/statusnet/scripts/maildaemon.php
|
|
||||||
|
|
||||||
3. Run whatever code you need to to update your aliases database. For
|
|
||||||
many mail servers (Postfix, Exim, Sendmail), this should work:
|
|
||||||
|
|
||||||
newaliases
|
|
||||||
|
|
||||||
You may need to restart your mail server for the new database to
|
|
||||||
take effect.
|
|
||||||
|
|
||||||
4. Set the following in your config.php file:
|
|
||||||
|
|
||||||
$config['mail']['domain'] = 'yourdomain.example.net';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Queues and daemons
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Some activities that StatusNet needs to do, like broadcast OStatus, SMS,
|
|
||||||
XMPP messages and TwitterBridge operations, can be 'queued' and done by
|
|
||||||
off-line bots instead.
|
|
||||||
|
|
||||||
Two mechanisms are available to achieve offline operations:
|
|
||||||
|
|
||||||
* New embedded OpportunisticQM plugin, which is enabled by default
|
|
||||||
* Legacy queuedaemon script, which can be enabled via config file.
|
|
||||||
|
|
||||||
### OpportunisticQM plugin
|
|
||||||
|
|
||||||
This plugin is enabled by default. It tries its best to do background
|
|
||||||
job during regular HTTP requests, like API or HTML pages calls.
|
|
||||||
|
|
||||||
Since queueing system is enabled by default, notices to be broadcasted
|
|
||||||
will be stored, by default, into DB (table queue_item).
|
|
||||||
|
|
||||||
Each time it can, OpportunisticQM will try to handle some of them.
|
|
||||||
|
|
||||||
This is a good solution whether you:
|
|
||||||
|
|
||||||
* have no access to command line (shared hosting)
|
|
||||||
* do not want to deal with long-running PHP processes
|
|
||||||
* run a low traffic GNU social instance
|
|
||||||
|
|
||||||
In other case, you really should consider enabling the queuedaemon for
|
|
||||||
performance reasons. Background daemons are necessary anyway if you wish
|
|
||||||
to use the Instant Messaging features such as communicating via XMPP.
|
|
||||||
|
|
||||||
### queuedaemon
|
|
||||||
|
|
||||||
If you want to use legacy queuedaemon, you must be able to run
|
|
||||||
long-running offline processes, either on your main Web server or on
|
|
||||||
another server you control. (Your other server will still need all the
|
|
||||||
above prerequisites, with the exception of Apache.) Installing on a
|
|
||||||
separate server is probably a good idea for high-volume sites.
|
|
||||||
|
|
||||||
1. You'll need the "CLI" (command-line interface) version of PHP
|
|
||||||
installed on whatever server you use.
|
|
||||||
|
|
||||||
Modern PHP versions in some operating systems have disabled functions
|
|
||||||
related to forking, which is required for daemons to operate. To make
|
|
||||||
this work, make sure that your php-cli config (/etc/php5/cli/php.ini)
|
|
||||||
does NOT have these functions listed under 'disable_functions':
|
|
||||||
|
|
||||||
* pcntl_fork, pcntl_wait, pcntl_wifexited, pcntl_wexitstatus,
|
|
||||||
pcntl_wifsignaled, pcntl_wtermsig
|
|
||||||
|
|
||||||
Other recommended settings for optimal performance are:
|
|
||||||
* mysqli.allow_persistent = On
|
|
||||||
* mysqli.reconnect = On
|
|
||||||
|
|
||||||
2. If you're using a separate server for queues, install StatusNet
|
|
||||||
somewhere on the server. You don't need to worry about the
|
|
||||||
.htaccess file, but make sure that your config.php file is close
|
|
||||||
to, or identical to, your Web server's version.
|
|
||||||
|
|
||||||
3. In your config.php files (both the Web server and the queues
|
|
||||||
server!), set the following variable:
|
|
||||||
|
|
||||||
$config['queue']['enabled'] = true;
|
|
||||||
$config['queue']['daemon'] = true;
|
|
||||||
|
|
||||||
You may also want to look at the 'daemon' section of this file for
|
|
||||||
more daemon options. Note that if you set the 'user' and/or 'group'
|
|
||||||
options, you'll need to create that user and/or group by hand.
|
|
||||||
They're not created automatically.
|
|
||||||
|
|
||||||
4. On the queues server, run the command scripts/startdaemons.sh.
|
|
||||||
|
|
||||||
This will run the queue handlers:
|
|
||||||
|
|
||||||
* queuedaemon.php - polls for queued items for inbox processing and
|
|
||||||
pushing out to OStatus, SMS, XMPP, etc.
|
|
||||||
* imdaemon.php - if an IM plugin is enabled (like XMPP)
|
|
||||||
* other daemons, like TwitterBridge ones, that you may have enabled
|
|
||||||
|
|
||||||
These daemons will automatically restart in most cases of failure
|
|
||||||
including memory leaks (if a memory_limit is set), but may still die
|
|
||||||
or behave oddly if they lose connections to the XMPP or queue servers.
|
|
||||||
|
|
||||||
It may be a good idea to use a daemon-monitoring service, like 'monit',
|
|
||||||
to check their status and keep them running.
|
|
||||||
|
|
||||||
All the daemons write their process IDs (pids) to /var/run/ by
|
|
||||||
default. This can be useful for starting, stopping, and monitoring the
|
|
||||||
daemons. If you are running multiple sites on the same machine, it will
|
|
||||||
be necessary to avoid collisions of these PID files by setting a site-
|
|
||||||
specific directory in config.php:
|
|
||||||
|
|
||||||
$config['daemon']['piddir'] = __DIR__ . '/../run/';
|
|
||||||
|
|
||||||
It is also possible to use a STOMP server instead of our kind of hacky
|
|
||||||
home-grown DB-based queue solution. This is strongly recommended for
|
|
||||||
best response time, especially when using XMPP.
|
|
||||||
|
|
||||||
Themes
|
|
||||||
------
|
|
||||||
|
|
||||||
Older themes (version 0.9.x and below) no longer work with StatusNet
|
|
||||||
1.0.x, due to major changes in the site layout. We ship with three new
|
|
||||||
themes for this version, 'neo', 'neo-blue' and 'neo-light'.
|
|
||||||
|
|
||||||
As of right now, your ability to change the theme is site-wide; users
|
|
||||||
can't choose their own theme. Additionally, the only thing you can
|
|
||||||
change in the theme is CSS stylesheets and some image files; you can't
|
|
||||||
change the HTML output, like adding or removing menu items.
|
|
||||||
|
|
||||||
You can choose a theme using the $config['site']['theme'] element in
|
|
||||||
the config.php file. See below for details.
|
|
||||||
|
|
||||||
You can add your own theme by making a sub-directory of the 'theme'
|
|
||||||
subdirectory with the name of your theme. Each theme can have the
|
|
||||||
following files:
|
|
||||||
|
|
||||||
display.css: a CSS2 file for "default" styling for all browsers.
|
|
||||||
logo.png: a logo image for the site.
|
|
||||||
default-avatar-profile.png: a 96x96 pixel image to use as the avatar for
|
|
||||||
users who don't upload their own.
|
|
||||||
default-avatar-stream.png: Ditto, but 48x48. For streams of notices.
|
|
||||||
default-avatar-mini.png: Ditto ditto, but 24x24. For subscriptions
|
|
||||||
listing on profile pages.
|
|
||||||
|
|
||||||
You may want to start by copying the files from the default theme to
|
|
||||||
your own directory.
|
|
||||||
|
|
||||||
Translation
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Translations in StatusNet use the gettext system <http://www.gnu.org/software/gettext/>.
|
|
||||||
Theoretically, you can add your own sub-directory to the locale/
|
|
||||||
subdirectory to add a new language to your system. You'll need to
|
|
||||||
compile the ".po" files into ".mo" files, however.
|
|
||||||
|
|
||||||
Contributions of translation information to StatusNet are very easy:
|
|
||||||
you can use the Web interface at translatewiki.net to add one
|
|
||||||
or a few or lots of new translations -- or even new languages. You can
|
|
||||||
also download more up-to-date .po files there, if you so desire.
|
|
||||||
|
|
||||||
For info on helping with translations, see http://status.net/wiki/Translations
|
|
||||||
|
|
||||||
Backups
|
|
||||||
-------
|
|
||||||
|
|
||||||
There is no built-in system for doing backups in StatusNet. You can make
|
|
||||||
backups of a working StatusNet system by backing up the database and
|
|
||||||
the Web directory. To backup the database use mysqldump <http://ur1.ca/7xo>
|
|
||||||
and to backup the Web directory, try tar.
|
|
||||||
|
|
||||||
Private
|
|
||||||
-------
|
|
||||||
|
|
||||||
The administrator can set the "private" flag for a site so that it's
|
|
||||||
not visible to non-logged-in users. (This is the default for new installs of version 1.0!)
|
|
||||||
|
|
||||||
This might be useful for workgroups who want to share a social
|
|
||||||
networking site for project management, but host it on a public
|
|
||||||
server.
|
|
||||||
|
|
||||||
Total privacy is attempted but not guaranteed or ensured. Private sites
|
|
||||||
currently don't work well with OStatus federation.
|
|
||||||
|
|
||||||
Access to file attachments can also be restricted to logged-in users only.
|
|
||||||
|
|
||||||
1. Add a directory outside the web root where your file uploads will be
|
|
||||||
stored. Usually a command like this will work:
|
|
||||||
|
|
||||||
mkdir /var/www/statusnet-files
|
|
||||||
|
|
||||||
2. Make the file uploads directory writeable by the web server. An
|
|
||||||
insecure way to do this is:
|
|
||||||
|
|
||||||
chmod a+x /var/www/statusnet-files
|
|
||||||
|
|
||||||
3. Tell StatusNet to use this directory for file uploads. Add a line
|
|
||||||
like this to your config.php:
|
|
||||||
|
|
||||||
$config['attachments']['dir'] = '/var/www/statusnet-files';
|
|
||||||
463
INSTALL.md
Normal file
463
INSTALL.md
Normal file
@@ -0,0 +1,463 @@
|
|||||||
|
TABLE OF CONTENTS
|
||||||
|
=================
|
||||||
|
* Prerequisites
|
||||||
|
- PHP modules
|
||||||
|
- Better performance
|
||||||
|
* Installation
|
||||||
|
- Getting it up and running
|
||||||
|
- Fancy URLs
|
||||||
|
- Themes
|
||||||
|
- Private
|
||||||
|
* Extra features
|
||||||
|
- Sphinx
|
||||||
|
- SMS
|
||||||
|
- Translation
|
||||||
|
- Queues and daemons
|
||||||
|
* After installation
|
||||||
|
- Backups
|
||||||
|
- Upgrading
|
||||||
|
* Additional configuration
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
=============
|
||||||
|
|
||||||
|
PHP modules
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The following software packages are *required* for this software to
|
||||||
|
run correctly.
|
||||||
|
|
||||||
|
- PHP 7+ PHP7.x is also supported.
|
||||||
|
- MariaDB 5+ MariaDB 10.x is also supported.
|
||||||
|
- Web server Apache, lighttpd and nginx will all work. CGI mode is
|
||||||
|
recommended and also some variant of 'suexec' (or a
|
||||||
|
proper setup php-fpm pool)
|
||||||
|
NOTE: mod_rewrite or its equivalent is extremely useful.
|
||||||
|
|
||||||
|
Your PHP installation must include the following PHP extensions for a
|
||||||
|
functional setup of GNU social:
|
||||||
|
|
||||||
|
- openssl (compiled in for Debian, enabled manually in Arch Linux)
|
||||||
|
- php-curl Fetching files by HTTP.
|
||||||
|
- php-exif Exchangeable image information.
|
||||||
|
- php-gd Image manipulation (scaling).
|
||||||
|
- php-intl Internationalization support (transliteration et al).
|
||||||
|
- php-json For WebFinger lookups and more.
|
||||||
|
- php-mbstring String manipulation
|
||||||
|
- php-mysql The native driver for MariaDB connections.
|
||||||
|
- php-gmp For Salmon signatures (part of OStatus)
|
||||||
|
- php-bcmath Arbitrary Precision Mathematics
|
||||||
|
- php-opcache Improved PHP performance by precompilation
|
||||||
|
- php-readline For interactive scripts
|
||||||
|
- php-xml XML parser
|
||||||
|
- php-ds Faster data structures
|
||||||
|
|
||||||
|
NOTE: Some distros require manual enabling in the relevant php.ini for some modules.
|
||||||
|
|
||||||
|
Better performance
|
||||||
|
------------------
|
||||||
|
|
||||||
|
For some functionality, you will also need the following extensions:
|
||||||
|
|
||||||
|
- opcache Improves performance a _lot_. Included in PHP, must be
|
||||||
|
enabled manually in php.ini for most distributions. Find
|
||||||
|
and set at least: opcache.enable=1
|
||||||
|
- mailparse Efficient parsing of email requires this extension.
|
||||||
|
Submission by email or SMS-over-email uses this.
|
||||||
|
- sphinx A client for the sphinx server, an alternative to MySQL
|
||||||
|
or Postgresql fulltext search. You will also need a
|
||||||
|
Sphinx server to serve the search queries.
|
||||||
|
- gettext For multiple languages. Default on many PHP installs;
|
||||||
|
will be emulated if not present.
|
||||||
|
- exif For thumbnails to be properly oriented.
|
||||||
|
- php-ds For faster data structures; will be emulated if not present.
|
||||||
|
|
||||||
|
You may also experience better performance from your site if you configure
|
||||||
|
a PHP cache/accelerator. Most distributions come with "opcache" support.
|
||||||
|
Enable it in your php.ini where it is documented together with its settings.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Getting it up and running
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Installing the basic GNU Social web component is relatively easy,
|
||||||
|
especially if you've previously installed PHP/MariaDB packages.
|
||||||
|
|
||||||
|
1. Unpack the tarball you downloaded on your Web server. Usually a
|
||||||
|
command like this will work:
|
||||||
|
|
||||||
|
tar zxf gnusocial-*.tar.gz
|
||||||
|
|
||||||
|
...which will make a gnusocial-x.y.z subdirectory in your current
|
||||||
|
directory. (If you don't have shell access on your Web server, you
|
||||||
|
may have to unpack the tarball on your local computer and FTP the
|
||||||
|
files to the server.)
|
||||||
|
|
||||||
|
2. Move the tarball to a directory of your choosing in your Web root
|
||||||
|
directory. Usually something like this will work:
|
||||||
|
|
||||||
|
mv gnusocial-x.y.z /var/www/gnusocial
|
||||||
|
|
||||||
|
This will often make your GNU Social instance available in the gnusocial
|
||||||
|
path of your server, like "http://example.net/gnusocial". "social" or
|
||||||
|
"blog" might also be good path names. If you know how to configure
|
||||||
|
virtual hosts on your web server, you can try setting up
|
||||||
|
"http://social.example.net/" or the like.
|
||||||
|
|
||||||
|
If you have "rewrite" support on your webserver, and you should,
|
||||||
|
then please enable this in order to make full use of your site. This
|
||||||
|
will enable "Fancy URL" support, which you can read more about if you
|
||||||
|
scroll down a bit in this document.
|
||||||
|
|
||||||
|
3. Make your target directory writeable by the Web server, please note
|
||||||
|
however that 'a+w' will give _all_ users write access and securing the
|
||||||
|
webserver is not within the scope of this document.
|
||||||
|
|
||||||
|
chmod a+w /var/www/gnusocial/
|
||||||
|
|
||||||
|
On some systems, this will work as a more secure alternative:
|
||||||
|
|
||||||
|
chgrp www-data /var/www/gnusocial/
|
||||||
|
chmod g+w /var/www/gnusocial/
|
||||||
|
|
||||||
|
If your Web server runs as another user besides "www-data", try
|
||||||
|
that user's default group instead. As a last resort, you can create
|
||||||
|
a new group like "gnusocial" and add the Web server's user to the group.
|
||||||
|
|
||||||
|
4. Create a database to hold your site data. Something like this
|
||||||
|
should work (you will be prompted for your database password):
|
||||||
|
|
||||||
|
mysqladmin -u "root" -p create social
|
||||||
|
|
||||||
|
Note that GNU Social should have its own database; you should not share
|
||||||
|
the database with another program. You can name it whatever you want,
|
||||||
|
though.
|
||||||
|
|
||||||
|
(If you don't have shell access to your server, you may need to use
|
||||||
|
a tool like phpMyAdmin to create a database. Check your hosting
|
||||||
|
service's documentation for how to create a new MariaDB database.)
|
||||||
|
|
||||||
|
5. Create a new database account that GNU Social will use to access the
|
||||||
|
database. If you have shell access, this will probably work from the
|
||||||
|
MariaDB shell:
|
||||||
|
|
||||||
|
GRANT ALL on social.*
|
||||||
|
TO 'social'@'localhost'
|
||||||
|
IDENTIFIED BY 'agoodpassword';
|
||||||
|
|
||||||
|
You should change the user identifier 'social' and 'agoodpassword'
|
||||||
|
to your preferred new database username and password. You may want to
|
||||||
|
test logging in to MariaDB as this new user.
|
||||||
|
|
||||||
|
6. In a browser, navigate to the GNU Social install script; something like:
|
||||||
|
|
||||||
|
https://social.example.net/install.php
|
||||||
|
|
||||||
|
Enter the database connection information and your site name. The
|
||||||
|
install program will configure your site and install the initial,
|
||||||
|
almost-empty database.
|
||||||
|
|
||||||
|
7. You should now be able to navigate to your social site's main directory
|
||||||
|
and see the "Public Timeline", which will probably be empty. You can
|
||||||
|
now register new user, post some notices, edit your profile, etc.
|
||||||
|
|
||||||
|
Fancy URLs
|
||||||
|
----------
|
||||||
|
|
||||||
|
By default, GNU Social will use URLs that include the main PHP program's
|
||||||
|
name in them. For example, a user's home profile might be found at either
|
||||||
|
of these URLS depending on the webserver's configuration and capabilities:
|
||||||
|
|
||||||
|
https://social.example.net/index.php/fred
|
||||||
|
https://social.example.net/index.php?p=fred
|
||||||
|
|
||||||
|
It's possible to configure the software to use fancy URLs so it looks like
|
||||||
|
this instead:
|
||||||
|
|
||||||
|
https://social.example.net/fred
|
||||||
|
|
||||||
|
These "fancy URLs" are more readable and memorable for users. To use
|
||||||
|
fancy URLs, you must either have Apache 2.x with .htaccess enabled and
|
||||||
|
mod_rewrite enabled, -OR- know how to configure "url redirection" in
|
||||||
|
your server (like lighttpd or nginx).
|
||||||
|
|
||||||
|
1. See the instructions for each respective webserver software:
|
||||||
|
* For Apache, inspect the "htaccess.sample" file and save it as
|
||||||
|
".htaccess" after making any necessary modifications. Our sample
|
||||||
|
file is well commented.
|
||||||
|
* For lighttpd, inspect the lighttpd.conf.example file and apply the
|
||||||
|
appropriate changes in your virtualhost configuration for lighttpd.
|
||||||
|
* For nginx, inspect the nginx.conf.sample file and apply the appropriate
|
||||||
|
changes.
|
||||||
|
* For other webservers, we gladly accept contributions of
|
||||||
|
server configuration examples.
|
||||||
|
|
||||||
|
2. Assuming your webserver is properly configured and have its settings
|
||||||
|
applied (remember to reload/restart it), you can add this to your
|
||||||
|
GNU social's config.php file:
|
||||||
|
$config['site']['fancy'] = true;
|
||||||
|
|
||||||
|
You should now be able to navigate to a "fancy" URL on your server,
|
||||||
|
like:
|
||||||
|
|
||||||
|
https://social.example.net/main/register
|
||||||
|
|
||||||
|
Themes
|
||||||
|
------
|
||||||
|
|
||||||
|
As of right now, your ability change the theme is limited to CSS
|
||||||
|
stylesheets and some image files; you can't change the HTML output,
|
||||||
|
like adding or removing menu items, without the help of a plugin.
|
||||||
|
|
||||||
|
You can choose a theme using the $config['site']['theme'] element in
|
||||||
|
the config.php file. See below for details.
|
||||||
|
|
||||||
|
You can add your own theme by making a sub-directory of the 'theme'
|
||||||
|
subdirectory with the name of your theme. Each theme can have the
|
||||||
|
following files:
|
||||||
|
|
||||||
|
display.css: a CSS2 file for "default" styling for all browsers.
|
||||||
|
logo.png: a logo image for the site.
|
||||||
|
default-avatar-profile.png: a 96x96 pixel image to use as the avatar for
|
||||||
|
users who don't upload their own.
|
||||||
|
default-avatar-stream.png: Ditto, but 48x48. For streams of notices.
|
||||||
|
default-avatar-mini.png: Ditto ditto, but 24x24. For subscriptions
|
||||||
|
listing on profile pages.
|
||||||
|
|
||||||
|
You may want to start by copying the files from the default theme to
|
||||||
|
your own directory.
|
||||||
|
|
||||||
|
Private
|
||||||
|
-------
|
||||||
|
|
||||||
|
A GNU social node can be configured as "private", which means it will not
|
||||||
|
federate with other nodes in the network. It is not a recommended method
|
||||||
|
of using GNU social and we cannot at the current state of development
|
||||||
|
guarantee that there are no leaks (what a public network sees as features,
|
||||||
|
private sites will likely see as bugs).
|
||||||
|
|
||||||
|
Private nodes are however an easy way to easily setup collaboration and
|
||||||
|
image sharing within a workgroup or a smaller community where federation
|
||||||
|
is not a desired feature. Also, it is possible to change this setting and
|
||||||
|
instantly gain full federation features.
|
||||||
|
|
||||||
|
Access to file attachments can also be restricted to logged-in users only:
|
||||||
|
|
||||||
|
1. Add a directory outside the web root where your file uploads will be
|
||||||
|
stored. Use this command as an initial guideline to create it:
|
||||||
|
|
||||||
|
mkdir /var/www/gnusocial-files
|
||||||
|
|
||||||
|
2. Make the file uploads directory writeable by the web server. An
|
||||||
|
insecure way to do this is (to do it properly, read up on UNIX file
|
||||||
|
permissions and configure your webserver accordingly):
|
||||||
|
|
||||||
|
chmod a+x /var/www/gnusocial-files
|
||||||
|
|
||||||
|
3. Tell GNU social to use this directory for file uploads. Add a line
|
||||||
|
like this to your config.php:
|
||||||
|
|
||||||
|
$config['attachments']['dir'] = '/var/www/gnusocial-files';
|
||||||
|
|
||||||
|
Extra features
|
||||||
|
==============
|
||||||
|
|
||||||
|
Sphinx
|
||||||
|
------
|
||||||
|
|
||||||
|
To use a Sphinx server to search users and notices, you'll need to
|
||||||
|
enable the SphinxSearch plugin. Add to your config.php:
|
||||||
|
|
||||||
|
addPlugin('SphinxSearch');
|
||||||
|
$config['sphinx']['server'] = 'searchhost.local';
|
||||||
|
|
||||||
|
You also need to install, compile and enable the sphinx pecl extension for
|
||||||
|
php on the client side, which itself depends on the sphinx development files.
|
||||||
|
|
||||||
|
See plugins/SphinxSearch/README for more details and server setup.
|
||||||
|
|
||||||
|
SMS
|
||||||
|
---
|
||||||
|
|
||||||
|
StatusNet supports a cheap-and-dirty system for sending update messages
|
||||||
|
to mobile phones and for receiving updates from the mobile. Instead of
|
||||||
|
sending through the SMS network itself, which is costly and requires
|
||||||
|
buy-in from the wireless carriers, it simply piggybacks on the email
|
||||||
|
gateways that many carriers provide to their customers. So, SMS
|
||||||
|
configuration is essentially email configuration.
|
||||||
|
|
||||||
|
Each user sends to a made-up email address, which they keep a secret.
|
||||||
|
Incoming email that is "From" the user's SMS email address, and "To"
|
||||||
|
the users' secret email address on the site's domain, will be
|
||||||
|
converted to a notice and stored in the DB.
|
||||||
|
|
||||||
|
For this to work, there *must* be a domain or sub-domain for which all
|
||||||
|
(or most) incoming email can pass through the incoming mail filter.
|
||||||
|
|
||||||
|
1. Run the SQL script carrier.sql in your StatusNet database. This will
|
||||||
|
usually work:
|
||||||
|
|
||||||
|
mysql -u "statusnetuser" --password="statusnetpassword" statusnet < db/carrier.sql
|
||||||
|
|
||||||
|
This will populate your database with a list of wireless carriers
|
||||||
|
that support email SMS gateways.
|
||||||
|
|
||||||
|
2. Make sure the maildaemon.php file is executable:
|
||||||
|
|
||||||
|
chmod +x scripts/maildaemon.php
|
||||||
|
|
||||||
|
Note that "daemon" is kind of a misnomer here; the script is more
|
||||||
|
of a filter than a daemon.
|
||||||
|
|
||||||
|
2. Edit /etc/aliases on your mail server and add the following line:
|
||||||
|
|
||||||
|
*: /path/to/statusnet/scripts/maildaemon.php
|
||||||
|
|
||||||
|
3. Run whatever code you need to to update your aliases database. For
|
||||||
|
many mail servers (Postfix, Exim, Sendmail), this should work:
|
||||||
|
|
||||||
|
newaliases
|
||||||
|
|
||||||
|
You may need to restart your mail server for the new database to
|
||||||
|
take effect.
|
||||||
|
|
||||||
|
4. Set the following in your config.php file:
|
||||||
|
|
||||||
|
$config['mail']['domain'] = 'yourdomain.example.net';
|
||||||
|
|
||||||
|
Translations
|
||||||
|
------------
|
||||||
|
|
||||||
|
For info on helping with translations, see the platform currently in use
|
||||||
|
for translations: https://www.transifex.com/projects/p/gnu-social/
|
||||||
|
|
||||||
|
Translations use the gettext system <http://www.gnu.org/software/gettext/>.
|
||||||
|
If you for some reason do not wish to sign up to the Transifex service,
|
||||||
|
you can review the files in the "locale/" sub-directory of GNU social.
|
||||||
|
Each plugin also has its own translation files.
|
||||||
|
|
||||||
|
To get your own site to use all the translated languages, and you are
|
||||||
|
tracking the git repo, you will need to install at least 'gettext' on
|
||||||
|
your system and then run:
|
||||||
|
$ make translations
|
||||||
|
|
||||||
|
Queues and daemons
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Some activities that StatusNet needs to do, like broadcast OStatus, SMS,
|
||||||
|
XMPP messages and TwitterBridge operations, can be 'queued' and done by
|
||||||
|
off-line bots instead.
|
||||||
|
|
||||||
|
Two mechanisms are available to achieve offline operations:
|
||||||
|
|
||||||
|
* New embedded OpportunisticQM plugin, which is enabled by default
|
||||||
|
* Legacy queuedaemon script, which can be enabled via config file.
|
||||||
|
|
||||||
|
### OpportunisticQM plugin
|
||||||
|
|
||||||
|
This plugin is enabled by default. It tries its best to do background
|
||||||
|
jobs during regular HTTP requests, like API or HTML pages calls.
|
||||||
|
|
||||||
|
Since queueing system is enabled by default, notices to be broadcasted
|
||||||
|
will be stored, by default, into DB (table queue_item).
|
||||||
|
|
||||||
|
Whenever it has time, OpportunisticQM will try to handle some of them.
|
||||||
|
|
||||||
|
This is a good solution whether you:
|
||||||
|
|
||||||
|
* have no access to command line (shared hosting)
|
||||||
|
* do not want to deal with long-running PHP processes
|
||||||
|
* run a low traffic GNU social instance
|
||||||
|
|
||||||
|
In other case, you really should consider enabling the queuedaemon for
|
||||||
|
performance reasons. Background daemons are necessary anyway if you wish
|
||||||
|
to use the Instant Messaging features such as communicating via XMPP.
|
||||||
|
|
||||||
|
### queuedaemon
|
||||||
|
|
||||||
|
If you want to use legacy queuedaemon, you must be able to run
|
||||||
|
long-running offline processes, either on your main Web server or on
|
||||||
|
another server you control. (Your other server will still need all the
|
||||||
|
above prerequisites, with the exception of Apache.) Installing on a
|
||||||
|
separate server is probably a good idea for high-volume sites.
|
||||||
|
|
||||||
|
1. You'll need the "CLI" (command-line interface) version of PHP
|
||||||
|
installed on whatever server you use.
|
||||||
|
|
||||||
|
Modern PHP versions in some operating systems have disabled functions
|
||||||
|
related to forking, which is required for daemons to operate. To make
|
||||||
|
this work, make sure that your php-cli config (/etc/php5/cli/php.ini)
|
||||||
|
does NOT have these functions listed under 'disable_functions':
|
||||||
|
|
||||||
|
* pcntl_fork, pcntl_wait, pcntl_wifexited, pcntl_wexitstatus,
|
||||||
|
pcntl_wifsignaled, pcntl_wtermsig
|
||||||
|
|
||||||
|
Other recommended settings for optimal performance are:
|
||||||
|
* mysqli.allow_persistent = On
|
||||||
|
* mysqli.reconnect = On
|
||||||
|
|
||||||
|
2. If you're using a separate server for queues, install StatusNet
|
||||||
|
somewhere on the server. You don't need to worry about the
|
||||||
|
.htaccess file, but make sure that your config.php file is close
|
||||||
|
to, or identical to, your Web server's version.
|
||||||
|
|
||||||
|
3. In your config.php files (on the server where you run the queue
|
||||||
|
daemon), set the following variable:
|
||||||
|
|
||||||
|
$config['queue']['daemon'] = true;
|
||||||
|
|
||||||
|
You may also want to look at the 'Queues and Daemons' section in
|
||||||
|
this file for more background processing options.
|
||||||
|
|
||||||
|
4. On the queues server, run the command scripts/startdaemons.sh.
|
||||||
|
|
||||||
|
This will run the queue handlers:
|
||||||
|
|
||||||
|
* queuedaemon.php - polls for queued items for inbox processing and
|
||||||
|
pushing out to OStatus, SMS, XMPP, etc.
|
||||||
|
* imdaemon.php - if an IM plugin is enabled (like XMPP)
|
||||||
|
* other daemons, like TwitterBridge ones, that you may have enabled
|
||||||
|
|
||||||
|
These daemons will automatically restart in most cases of failure
|
||||||
|
including memory leaks (if a memory_limit is set), but may still die
|
||||||
|
or behave oddly if they lose connections to the XMPP or queue servers.
|
||||||
|
|
||||||
|
It may be a good idea to use a daemon-monitoring service, like 'monit',
|
||||||
|
to check their status and keep them running.
|
||||||
|
|
||||||
|
All the daemons write their process IDs (pids) to /var/run/ by
|
||||||
|
default. This can be useful for starting, stopping, and monitoring the
|
||||||
|
daemons. If you are running multiple sites on the same machine, it will
|
||||||
|
be necessary to avoid collisions of these PID files by setting a site-
|
||||||
|
specific directory in config.php:
|
||||||
|
|
||||||
|
$config['daemon']['piddir'] = __DIR__ . '/../run/';
|
||||||
|
|
||||||
|
It is also possible to use a STOMP server instead of our kind of hacky
|
||||||
|
home-grown DB-based queue solution. This is strongly recommended for
|
||||||
|
best response time, especially when using XMPP.
|
||||||
|
|
||||||
|
After installation
|
||||||
|
==================
|
||||||
|
|
||||||
|
Backups
|
||||||
|
-------
|
||||||
|
|
||||||
|
There is no built-in system for doing backups in GNU social. You can make
|
||||||
|
backups of a working StatusNet system by backing up the database and
|
||||||
|
the Web directory. To backup the database use mysqldump <https://mariadb.com/kb/en/mariadb/mysqldump/>
|
||||||
|
and to backup the Web directory, try tar.
|
||||||
|
|
||||||
|
Upgrading
|
||||||
|
---------
|
||||||
|
|
||||||
|
Upgrading is strongly recommended to stay up to date with security fixes
|
||||||
|
and new features. For instructions on how to upgrade GNU social code,
|
||||||
|
please see the UPGRADE file.
|
||||||
|
|
||||||
|
Additional configuration
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Please refer to DOCUMENTATION/SYSTEM_ADMINISTRATORS/CONFIGURE for information.
|
||||||
44
PLUGINS.txt
44
PLUGINS.txt
@@ -1,44 +0,0 @@
|
|||||||
Plugins
|
|
||||||
=======
|
|
||||||
|
|
||||||
Beginning with the 0.7.x branch, StatusNet has supported a simple but
|
|
||||||
powerful plugin architecture. Important events in the code are named,
|
|
||||||
like 'StartNoticeSave', and other software can register interest
|
|
||||||
in those events. When the events happen, the other software is called
|
|
||||||
and has a choice of accepting or rejecting the events.
|
|
||||||
|
|
||||||
In the simplest case, you can add a function to config.php and use the
|
|
||||||
Event::addHandler() function to hook an event:
|
|
||||||
|
|
||||||
function AddGoogleLink($action)
|
|
||||||
{
|
|
||||||
$action->menuItem('http://www.google.com/', _('Google'), _('Search engine'));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::addHandler('EndPrimaryNav', 'AddGoogleLink');
|
|
||||||
|
|
||||||
This adds a menu item to the end of the main navigation menu. You can
|
|
||||||
see the list of existing events, and parameters that handlers must
|
|
||||||
implement, in EVENTS.txt.
|
|
||||||
|
|
||||||
The Plugin class in lib/plugin.php makes it easier to write more
|
|
||||||
complex plugins. Sub-classes can just create methods named
|
|
||||||
'onEventName', where 'EventName' is the name of the event (case
|
|
||||||
matters!). These methods will be automatically registered as event
|
|
||||||
handlers by the Plugin constructor (which you must call from your own
|
|
||||||
class's constructor).
|
|
||||||
|
|
||||||
Several example plugins are included in the plugins/ directory. You
|
|
||||||
can enable a plugin with the following line in config.php:
|
|
||||||
|
|
||||||
addPlugin('Example', array('param1' => 'value1',
|
|
||||||
'param2' => 'value2'));
|
|
||||||
|
|
||||||
This will look for and load files named 'ExamplePlugin.php' or
|
|
||||||
'Example/ExamplePlugin.php' either in the plugins/ directory (for
|
|
||||||
plugins that ship with StatusNet) or in the local/ directory (for
|
|
||||||
plugins you write yourself or that you get from somewhere else) or
|
|
||||||
local/plugins/.
|
|
||||||
|
|
||||||
Plugins are documented in their own directories.
|
|
||||||
162
README.md
162
README.md
@@ -1,27 +1,22 @@
|
|||||||
# GNU social 1.1.3
|
# GNU social 1.20.x
|
||||||
February 2015-02-27
|
(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,27 +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 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)
|
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
|
|
||||||
@@ -140,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@gitorious.org:social/mainline.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.1.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
|
||||||
|
|
||||||
@@ -159,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://bugz.foocorp.net/>
|
making things better. <https://notabug.org/diogo/gnu-social/issues>
|
||||||
* Patches are welcome, preferrably to our repository on Gitorious. <https://gitorious.org/social/mainline>
|
* 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.
|
|
||||||
99
UPGRADE
99
UPGRADE
@@ -1,99 +0,0 @@
|
|||||||
Upgrading
|
|
||||||
=========
|
|
||||||
|
|
||||||
StatusNet 1.1.1 to GNU social
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
We cannot support migrating from any other version of StatusNet than
|
|
||||||
1.1.1. If you are running a StatusNet version lower than this, please
|
|
||||||
follow the upgrade procedures for each respective StatusNet version.
|
|
||||||
|
|
||||||
You are now running StatusNet 1.1.1 and want to migrate to GNU social.
|
|
||||||
Beware there may be changes in minimum required version of PHP and the
|
|
||||||
modules used, so double-check the INSTALL file's requirements list.
|
|
||||||
|
|
||||||
Before you begin: Make backups. Always make backups. Of your entire
|
|
||||||
directory structure and the database too. All tables. All data. Alles.
|
|
||||||
|
|
||||||
0. Stop your queue daemons 'php scripts/stopdaemon.php' should do it.
|
|
||||||
Not everyone runs queue daemons, but the above command won't hurt.
|
|
||||||
|
|
||||||
1. Unpack your GNU social code to a fresh directory.
|
|
||||||
|
|
||||||
2. Synchronize your local files to the GNU social directory. These
|
|
||||||
will be the local files such as avatars, config and files:
|
|
||||||
|
|
||||||
avatar/*
|
|
||||||
background/*
|
|
||||||
file/*
|
|
||||||
local/*
|
|
||||||
.htaccess
|
|
||||||
config.php
|
|
||||||
|
|
||||||
3. Replace your old StatusNet directory with the new GNU social
|
|
||||||
directory in your webserver root.
|
|
||||||
|
|
||||||
4. Run the upgrade script: 'php scripts/upgrade.php'
|
|
||||||
|
|
||||||
5. Start your queue daemons: 'php scripts/startdaemons.php'
|
|
||||||
|
|
||||||
6. Report any issues at https://bugz.foocorp.net/ (tag GNU social)
|
|
||||||
|
|
||||||
|
|
||||||
Legacy StatusNet instructions
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
These instructions are here for historical and perhaps informational
|
|
||||||
purposes.
|
|
||||||
|
|
||||||
If you've been using StatusNet 1.0 or lower, or if you've
|
|
||||||
been tracking the "git" version of the software, you will probably
|
|
||||||
want to upgrade and keep your existing data. Try these step-by-step
|
|
||||||
instructions; read to the end first before trying them.
|
|
||||||
|
|
||||||
0. Download StatusNet and set up all the prerequisites as if you were
|
|
||||||
doing a new install.
|
|
||||||
1. Make backups of both your database and your Web directory. UNDER NO
|
|
||||||
CIRCUMSTANCES should you try to do an upgrade without a known-good
|
|
||||||
backup. You have been warned.
|
|
||||||
2. Shut down Web access to your site, either by turning off your Web
|
|
||||||
server or by redirecting all pages to a "sorry, under maintenance"
|
|
||||||
page.
|
|
||||||
3. Shut down XMPP access to your site, typically by shutting down the
|
|
||||||
xmppdaemon.php process and all other daemons that you're running.
|
|
||||||
If you've got "monit" or "cron" automatically restarting your
|
|
||||||
daemons, make sure to turn that off, too.
|
|
||||||
4. Shut down SMS and email access to your site. The easy way to do
|
|
||||||
this is to comment out the line piping incoming email to your
|
|
||||||
maildaemon.php file, and running something like "newaliases".
|
|
||||||
5. Once all writing processes to your site are turned off, make a
|
|
||||||
final backup of the Web directory and database.
|
|
||||||
6. Move your StatusNet directory to a backup spot, like "statusnet.bak".
|
|
||||||
7. Unpack your StatusNet 1.1.1 tarball and move it to "statusnet" or
|
|
||||||
wherever your code used to be.
|
|
||||||
8. Copy the config.php file and the contents of the avatar/, background/,
|
|
||||||
file/, and local/ subdirectories from your old directory to your new
|
|
||||||
directory.
|
|
||||||
9. Copy htaccess.sample to .htaccess in the new directory. Change the
|
|
||||||
RewriteBase to use the correct path.
|
|
||||||
10. Upgrade the database.
|
|
||||||
|
|
||||||
NOTE: this step is destructive and cannot be
|
|
||||||
reversed. YOU CAN EASILY DESTROY YOUR SITE WITH THIS STEP. Don't
|
|
||||||
do it without a known-good backup!
|
|
||||||
|
|
||||||
In your new StatusNet 1.1.1 directory and AFTER YOU MAKE A
|
|
||||||
BACKUP run the upgrade.php script like this:
|
|
||||||
|
|
||||||
php ./scripts/upgrade.php
|
|
||||||
|
|
||||||
11. Use mysql or psql client to log into your database and make sure that
|
|
||||||
the notice, user, profile, subscription etc. tables are non-empty.
|
|
||||||
12. Turn back on the Web server, and check that things still work.
|
|
||||||
13. Turn back on XMPP bots and email maildaemon.
|
|
||||||
|
|
||||||
NOTE: the 1.0.0 version of StatusNet changed the URLs for all admin
|
|
||||||
panels from /admin/* to /panel/*. This now allows the (popular)
|
|
||||||
username 'admin', but blocks the considerably less popular username
|
|
||||||
'panel'. If you have an existing user named 'panel', you should rename
|
|
||||||
them before upgrading.
|
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -35,38 +35,24 @@
|
|||||||
* @link http://status.net
|
* @link http://status.net
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); }
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
|
|
||||||
class AllAction extends ProfileAction
|
class AllAction extends ShowstreamAction
|
||||||
{
|
{
|
||||||
var $notice;
|
public function getStream()
|
||||||
|
|
||||||
protected function prepare(array $args=array())
|
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
|
||||||
|
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
if (!empty($user) && $user->streamModeOnly()) {
|
|
||||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||||
} else {
|
} else {
|
||||||
$stream = new ThreadingInboxNoticeStream($this->target, $this->scoped);
|
$stream = new ThreadingInboxNoticeStream($this->target, $this->scoped);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
|
return $stream;
|
||||||
NOTICES_PER_PAGE + 1);
|
|
||||||
|
|
||||||
if ($this->page > 1 && $this->notice->N == 0) {
|
|
||||||
// TRANS: Client error when page not found (404).
|
|
||||||
$this->clientError(_('No such page.'), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
if (!empty($this->scoped) && $this->scoped->id == $this->target->id) {
|
if (!empty($this->scoped) && $this->scoped->sameAs($this->target)) {
|
||||||
// TRANS: Title of a user's own start page.
|
// TRANS: Title of a user's own start page.
|
||||||
return _('Home timeline');
|
return _('Home timeline');
|
||||||
} else {
|
} else {
|
||||||
@@ -83,44 +69,44 @@ class AllAction extends ProfileAction
|
|||||||
common_local_url(
|
common_local_url(
|
||||||
'ApiTimelineFriends', array(
|
'ApiTimelineFriends', array(
|
||||||
'format' => 'as',
|
'format' => 'as',
|
||||||
'id' => $this->target->nickname
|
'id' => $this->target->getNickname()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
// TRANS: %s is user nickname.
|
// TRANS: %s is user nickname.
|
||||||
sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->nickname)),
|
sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->getNickname())),
|
||||||
new Feed(Feed::RSS1,
|
new Feed(Feed::RSS1,
|
||||||
common_local_url(
|
common_local_url(
|
||||||
'allrss', array(
|
'allrss', array(
|
||||||
'nickname' =>
|
'nickname' =>
|
||||||
$this->target->nickname)
|
$this->target->getNickname())
|
||||||
),
|
),
|
||||||
// TRANS: %s is user nickname.
|
// TRANS: %s is user nickname.
|
||||||
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->target->nickname)),
|
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->target->getNickname())),
|
||||||
new Feed(Feed::RSS2,
|
new Feed(Feed::RSS2,
|
||||||
common_local_url(
|
common_local_url(
|
||||||
'ApiTimelineFriends', array(
|
'ApiTimelineFriends', array(
|
||||||
'format' => 'rss',
|
'format' => 'rss',
|
||||||
'id' => $this->target->nickname
|
'id' => $this->target->getNickname()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
// TRANS: %s is user nickname.
|
// TRANS: %s is user nickname.
|
||||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->nickname)),
|
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->getNickname())),
|
||||||
new Feed(Feed::ATOM,
|
new Feed(Feed::ATOM,
|
||||||
common_local_url(
|
common_local_url(
|
||||||
'ApiTimelineFriends', array(
|
'ApiTimelineFriends', array(
|
||||||
'format' => 'atom',
|
'format' => 'atom',
|
||||||
'id' => $this->target->nickname
|
'id' => $this->target->getNickname()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
// TRANS: %s is user nickname.
|
// TRANS: %s is user nickname.
|
||||||
sprintf(_('Feed for friends of %s (Atom)'), $this->target->nickname))
|
sprintf(_('Feed for friends of %s (Atom)'), $this->target->getNickname()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showEmptyListMessage()
|
function showEmptyListMessage()
|
||||||
{
|
{
|
||||||
// TRANS: Empty list message. %s is a user nickname.
|
// TRANS: Empty list message. %s is a user nickname.
|
||||||
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->target->nickname) . ' ';
|
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->target->getNickname()) . ' ';
|
||||||
|
|
||||||
if (common_logged_in()) {
|
if (common_logged_in()) {
|
||||||
if ($this->target->id === $this->scoped->id) {
|
if ($this->target->id === $this->scoped->id) {
|
||||||
@@ -130,12 +116,12 @@ class AllAction extends ProfileAction
|
|||||||
} else {
|
} else {
|
||||||
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@".
|
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@".
|
||||||
// TRANS: This message contains Markdown links. Keep "](" together.
|
// TRANS: This message contains Markdown links. Keep "](" together.
|
||||||
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->target->nickname, $this->target->nickname, '@' . $this->target->nickname);
|
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->target->getNickname(), $this->target->getNickname(), '@' . $this->target->getNickname());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TRANS: Encouragement displayed on empty timeline user pages for anonymous users.
|
// TRANS: Encouragement displayed on empty timeline user pages for anonymous users.
|
||||||
// TRANS: %s is a user nickname. This message contains Markdown links. Keep "](" together.
|
// TRANS: %s is a user nickname. This message contains Markdown links. Keep "](" together.
|
||||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->target->nickname);
|
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->target->getNickname());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->elementStart('div', 'guide');
|
$this->elementStart('div', 'guide');
|
||||||
@@ -146,19 +132,10 @@ class AllAction extends ProfileAction
|
|||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
if (Event::handle('StartShowAllContent', array($this))) {
|
if (Event::handle('StartShowAllContent', array($this))) {
|
||||||
|
if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
|
||||||
$profile = null;
|
|
||||||
|
|
||||||
$current_user = common_current_user();
|
|
||||||
|
|
||||||
if (!empty($current_user)) {
|
|
||||||
$profile = $current_user->getProfile();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($current_user) && $current_user->streamModeOnly()) {
|
|
||||||
$nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
|
$nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
|
||||||
} else {
|
} else {
|
||||||
$nl = new ThreadedNoticeList($this->notice, $this, $profile);
|
$nl = new ThreadedNoticeList($this->notice, $this, $this->scoped);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $nl->show();
|
||||||
@@ -169,7 +146,7 @@ class AllAction extends ProfileAction
|
|||||||
|
|
||||||
$this->pagination(
|
$this->pagination(
|
||||||
$this->page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$this->page, 'all', array('nickname' => $this->target->nickname)
|
$this->page, 'all', array('nickname' => $this->target->getNickname())
|
||||||
);
|
);
|
||||||
|
|
||||||
Event::handle('EndShowAllContent', array($this));
|
Event::handle('EndShowAllContent', array($this));
|
||||||
@@ -193,12 +170,6 @@ class AllAction extends ProfileAction
|
|||||||
}
|
}
|
||||||
$ibs->show();
|
$ibs->show();
|
||||||
}
|
}
|
||||||
// XXX: make this a little more convenient
|
|
||||||
|
|
||||||
if (!common_config('performance', 'high')) {
|
|
||||||
$pop = new InboxTagCloudSection($this, $this->target);
|
|
||||||
$pop->show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,7 @@
|
|||||||
* 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('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RSS feed for user and friends timeline.
|
* RSS feed for user and friends timeline.
|
||||||
@@ -46,52 +42,12 @@ require_once INSTALLDIR.'/lib/rssaction.php';
|
|||||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
class AllrssAction extends Rss10Action
|
class AllrssAction extends TargetedRss10Action
|
||||||
{
|
{
|
||||||
var $user = null;
|
protected function getNotices()
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialization.
|
|
||||||
*
|
|
||||||
* @param array $args Web and URL arguments
|
|
||||||
*
|
|
||||||
* @return boolean false if user doesn't exist
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function prepare($args)
|
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||||
$nickname = $this->trimmed('nickname');
|
return $stream->getNotices(0, $this->limit)->fetchAll();
|
||||||
$this->user = User::getKV('nickname', $nickname);
|
|
||||||
|
|
||||||
if (!$this->user) {
|
|
||||||
// TRANS: Client error when user not found for an rss related action.
|
|
||||||
$this->clientError(_('No such user.'));
|
|
||||||
} else {
|
|
||||||
$this->notices = $this->getNotices($this->limit);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get notices
|
|
||||||
*
|
|
||||||
* @param integer $limit max number of notices to return
|
|
||||||
*
|
|
||||||
* @return array notices
|
|
||||||
*/
|
|
||||||
function getNotices($limit=0)
|
|
||||||
{
|
|
||||||
$stream = new InboxNoticeStream($this->user->getProfile());
|
|
||||||
$notice = $stream->getNotices(0, $limit, null, null);
|
|
||||||
|
|
||||||
$notices = array();
|
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
|
||||||
$notices[] = clone($notice);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $notices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,33 +57,17 @@ class AllrssAction extends Rss10Action
|
|||||||
*/
|
*/
|
||||||
function getChannel()
|
function getChannel()
|
||||||
{
|
{
|
||||||
$user = $this->user;
|
|
||||||
$c = array('url' => common_local_url('allrss',
|
$c = array('url' => common_local_url('allrss',
|
||||||
array('nickname' =>
|
array('nickname' =>
|
||||||
$user->nickname)),
|
$this->target->getNickname())),
|
||||||
// TRANS: Message is used as link title. %s is a user nickname.
|
// TRANS: Message is used as link title. %s is a user nickname.
|
||||||
'title' => sprintf(_('%s and friends'), $user->nickname),
|
'title' => sprintf(_('%s and friends'), $this->target->getNickname()),
|
||||||
'link' => common_local_url('all',
|
'link' => common_local_url('all',
|
||||||
array('nickname' =>
|
array('nickname' =>
|
||||||
$user->nickname)),
|
$this->target->getNickname())),
|
||||||
// TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
|
// TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
|
||||||
'description' => sprintf(_('Updates from %1$s and friends on %2$s!'),
|
'description' => sprintf(_('Updates from %1$s and friends on %2$s!'),
|
||||||
$user->nickname, common_config('site', 'name')));
|
$this->target->getNickname(), common_config('site', 'name')));
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get image.
|
|
||||||
*
|
|
||||||
* @return string user avatar URL or null
|
|
||||||
*/
|
|
||||||
function getImage()
|
|
||||||
{
|
|
||||||
$user = $this->user;
|
|
||||||
$profile = $user->getProfile();
|
|
||||||
if (!$profile) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return $profile->avatarUrl(AVATAR_PROFILE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,27 +49,39 @@ if (!defined('STATUSNET')) {
|
|||||||
*/
|
*/
|
||||||
class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Return true if read only.
|
||||||
|
*
|
||||||
|
* MAY override
|
||||||
|
*
|
||||||
|
* @param array $args other arguments
|
||||||
|
*
|
||||||
|
* @return boolean is read only action?
|
||||||
|
*/
|
||||||
|
public function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the request
|
* Handle the request
|
||||||
*
|
*
|
||||||
* Return some Twitter-ish data about API limits
|
* Return some Twitter-ish data about API limits
|
||||||
*
|
*
|
||||||
* @param array $args $_REQUEST data (unused)
|
|
||||||
*
|
|
||||||
* @return void
|
* @return void
|
||||||
|
* @throws ClientException
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
protected function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if (!in_array($this->format, array('xml', 'json'))) {
|
if (!in_array($this->format, ['xml', 'json'])) {
|
||||||
$this->clientError(
|
$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.
|
||||||
_('API method not found.'),
|
_('API method not found.'),
|
||||||
404,
|
404,
|
||||||
$this->format
|
$this->format
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$reset = new DateTime();
|
$reset = new DateTime();
|
||||||
@@ -79,44 +91,31 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
|||||||
|
|
||||||
if ($this->format == 'xml') {
|
if ($this->format == 'xml') {
|
||||||
$this->elementStart('hash');
|
$this->elementStart('hash');
|
||||||
$this->element('remaining-hits', array('type' => 'integer'), 150);
|
$this->element('remaining-hits', ['type' => 'integer'], "150");
|
||||||
$this->element('hourly-limit', array('type' => 'integer'), 150);
|
$this->element('hourly-limit', ['type' => 'integer'], "150");
|
||||||
$this->element(
|
$this->element(
|
||||||
'reset-time', array('type' => 'datetime'),
|
'reset-time',
|
||||||
|
['type' => 'datetime'],
|
||||||
common_date_iso8601($reset->format('r'))
|
common_date_iso8601($reset->format('r'))
|
||||||
);
|
);
|
||||||
$this->element(
|
$this->element(
|
||||||
'reset_time_in_seconds',
|
'reset_time_in_seconds',
|
||||||
array('type' => 'integer'),
|
['type' => 'integer'],
|
||||||
strtotime('+1 hour')
|
strtotime('+1 hour')
|
||||||
);
|
);
|
||||||
$this->elementEnd('hash');
|
$this->elementEnd('hash');
|
||||||
} elseif ($this->format == 'json') {
|
} elseif ($this->format == 'json') {
|
||||||
$out = array(
|
$out = [
|
||||||
'reset_time_in_seconds' => strtotime('+1 hour'),
|
'reset_time_in_seconds' => strtotime('+1 hour'),
|
||||||
'remaining_hits' => 150,
|
'remaining_hits' => 150,
|
||||||
'hourly_limit' => 150,
|
'hourly_limit' => 150,
|
||||||
'reset_time' => common_date_rfc2822(
|
'reset_time' => common_date_rfc2822(
|
||||||
$reset->format('r')
|
$reset->format('r')
|
||||||
)
|
)
|
||||||
);
|
];
|
||||||
print json_encode($out);
|
print json_encode($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->endDocument($this->format);
|
$this->endDocument($this->format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if read only.
|
|
||||||
*
|
|
||||||
* MAY override
|
|
||||||
*
|
|
||||||
* @param array $args other arguments
|
|
||||||
*
|
|
||||||
* @return boolean is read only action?
|
|
||||||
*/
|
|
||||||
function isReadOnly($args)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StatusNet, the distributed open-source microblogging tool
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
*
|
*
|
||||||
@@ -132,9 +131,6 @@ class ApiAccountRegisterAction extends ApiAction
|
|||||||
!common_valid_http_url($homepage)) {
|
!common_valid_http_url($homepage)) {
|
||||||
// TRANS: Form validation error displayed when trying to register with an invalid homepage URL.
|
// TRANS: Form validation error displayed when trying to register with an invalid homepage URL.
|
||||||
$this->clientError(_('Homepage is not a valid URL.'), 400);
|
$this->clientError(_('Homepage is not a valid URL.'), 400);
|
||||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
|
||||||
// TRANS: Form validation error displayed when trying to register with a too long full name.
|
|
||||||
$this->clientError(_('Full name is too long (maximum 255 characters).'), 400);
|
|
||||||
} else if (Profile::bioTooLong($bio)) {
|
} else if (Profile::bioTooLong($bio)) {
|
||||||
// TRANS: Form validation error on registration page when providing too long a bio text.
|
// TRANS: Form validation error on registration page when providing too long a bio text.
|
||||||
// TRANS: %d is the maximum number of characters for bio; used for plural.
|
// TRANS: %d is the maximum number of characters for bio; used for plural.
|
||||||
@@ -142,9 +138,6 @@ class ApiAccountRegisterAction extends ApiAction
|
|||||||
'Bio is too long (maximum %d characters).',
|
'Bio is too long (maximum %d characters).',
|
||||||
Profile::maxBio()),
|
Profile::maxBio()),
|
||||||
Profile::maxBio()), 400);
|
Profile::maxBio()), 400);
|
||||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
|
||||||
// TRANS: Form validation error displayed when trying to register with a too long location.
|
|
||||||
$this->clientError(_('Location is too long (maximum 255 characters).'), 400);
|
|
||||||
} else if (strlen($password) < 6) {
|
} else if (strlen($password) < 6) {
|
||||||
// TRANS: Form validation error displayed when trying to register with too short a password.
|
// TRANS: Form validation error displayed when trying to register with too short a password.
|
||||||
$this->clientError(_('Password must be 6 or more characters.'), 400);
|
$this->clientError(_('Password must be 6 or more characters.'), 400);
|
||||||
@@ -156,28 +149,25 @@ class ApiAccountRegisterAction extends ApiAction
|
|||||||
// annoy spammers
|
// annoy spammers
|
||||||
sleep(7);
|
sleep(7);
|
||||||
|
|
||||||
if ($user = User::register(array('nickname' => $nickname,
|
if (Event::handle('APIStartRegistrationTry', array($this))) {
|
||||||
|
try {
|
||||||
|
$user = User::register(array('nickname' => $nickname,
|
||||||
'password' => $password,
|
'password' => $password,
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'fullname' => $fullname,
|
'fullname' => $fullname,
|
||||||
'homepage' => $homepage,
|
'homepage' => $homepage,
|
||||||
'bio' => $bio,
|
'bio' => $bio,
|
||||||
'location' => $location,
|
'location' => $location,
|
||||||
'code' => $this->code))) {
|
'code' => $this->code));
|
||||||
if (!$user instanceof User) {
|
|
||||||
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
|
|
||||||
$this->clientError(_('Invalid username or password.'), 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::handle('EndRegistrationTry', array($this));
|
Event::handle('EndRegistrationTry', array($this));
|
||||||
|
|
||||||
$this->initDocument('json');
|
$this->initDocument('json');
|
||||||
$this->showJsonObjects($this->twitterUserArray($user->getProfile()));
|
$this->showJsonObjects($this->twitterUserArray($user->getProfile()));
|
||||||
$this->endDocument('json');
|
$this->endDocument('json');
|
||||||
|
|
||||||
} else {
|
} catch (Exception $e) {
|
||||||
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
|
$this->clientError($e->getMessage(), 400);
|
||||||
$this->clientError(_('Invalid username or password.'), 400);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -96,21 +96,12 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
|
|||||||
|
|
||||||
$original = clone($profile);
|
$original = clone($profile);
|
||||||
|
|
||||||
if (!empty($this->name)) {
|
|
||||||
$profile->fullname = $this->name;
|
$profile->fullname = $this->name;
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->url)) {
|
|
||||||
$profile->homepage = $this->url;
|
$profile->homepage = $this->url;
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->description)) {
|
|
||||||
$profile->bio = $this->description;
|
$profile->bio = $this->description;
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->location)) {
|
|
||||||
$profile->location = $this->location;
|
$profile->location = $this->location;
|
||||||
|
|
||||||
|
if (!empty($this->location)) {
|
||||||
$loc = Location::fromName($this->location);
|
$loc = Location::fromName($this->location);
|
||||||
|
|
||||||
if (!empty($loc)) {
|
if (!empty($loc)) {
|
||||||
@@ -119,6 +110,12 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
|
|||||||
$profile->location_id = $loc->location_id;
|
$profile->location_id = $loc->location_id;
|
||||||
$profile->location_ns = $loc->location_ns;
|
$profile->location_ns = $loc->location_ns;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// location is empty so reset the extrapolated information too
|
||||||
|
$profile->lat = '';
|
||||||
|
$profile->lon = '';
|
||||||
|
$profile->location_id = '';
|
||||||
|
$profile->location_ns = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $profile->update($original);
|
$result = $profile->update($original);
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|
||||||
|
|||||||
@@ -49,16 +49,9 @@ class ApiconversationAction extends ApiAuthAction
|
|||||||
protected $conversation = null;
|
protected $conversation = null;
|
||||||
protected $notices = null;
|
protected $notices = null;
|
||||||
|
|
||||||
/**
|
protected function prepare(array $args=array())
|
||||||
* For initializing members of the class.
|
|
||||||
*
|
|
||||||
* @param array $argarray misc. arguments
|
|
||||||
*
|
|
||||||
* @return boolean true
|
|
||||||
*/
|
|
||||||
function prepare($argarray)
|
|
||||||
{
|
{
|
||||||
parent::prepare($argarray);
|
parent::prepare($args);
|
||||||
|
|
||||||
$convId = $this->trimmed('id');
|
$convId = $this->trimmed('id');
|
||||||
|
|
||||||
|
|||||||
@@ -29,9 +29,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows the authenticating users to follow (subscribe) the user specified in
|
* Allows the authenticating users to follow (subscribe) the user specified in
|
||||||
@@ -90,7 +88,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
|
|||||||
$this->clientError(_('Could not follow user: profile not found.'), 403);
|
$this->clientError(_('Could not follow user: profile not found.'), 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->user->isSubscribed($this->other)) {
|
if ($this->scoped->isSubscribed($this->other)) {
|
||||||
$errmsg = sprintf(
|
$errmsg = sprintf(
|
||||||
// TRANS: Client error displayed when trying to follow a user that's already being followed.
|
// TRANS: Client error displayed when trying to follow a user that's already being followed.
|
||||||
// TRANS: %s is the nickname of the user that is already being followed.
|
// TRANS: %s is the nickname of the user that is already being followed.
|
||||||
@@ -101,9 +99,9 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Subscription::start($this->user->getProfile(), $this->other);
|
Subscription::start($this->scoped, $this->other);
|
||||||
} catch (Exception $e) {
|
} catch (AlreadyFulfilledException $e) {
|
||||||
$this->clientError($e->getMessage(), 403);
|
$this->clientError($e->getMessage(), 409);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->initDocument($this->format);
|
$this->initDocument($this->format);
|
||||||
|
|||||||
@@ -29,9 +29,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows the authenticating users to unfollow (unsubscribe) the user specified in
|
* Allows the authenticating users to unfollow (unsubscribe) the user specified in
|
||||||
@@ -48,7 +46,9 @@ if (!defined('STATUSNET')) {
|
|||||||
*/
|
*/
|
||||||
class ApiFriendshipsDestroyAction extends ApiAuthAction
|
class ApiFriendshipsDestroyAction extends ApiAuthAction
|
||||||
{
|
{
|
||||||
var $other = null;
|
protected $needPost = true;
|
||||||
|
|
||||||
|
protected $other = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take arguments for running
|
* Take arguments for running
|
||||||
@@ -58,11 +58,10 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
|
|||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
protected function prepare(array $args=array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
$this->user = $this->auth_user;
|
|
||||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -73,58 +72,40 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
|
|||||||
*
|
*
|
||||||
* Check the format and show the user info
|
* Check the format and show the user info
|
||||||
*
|
*
|
||||||
* @param array $args $_REQUEST data (unused)
|
|
||||||
*
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
protected function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
|
|
||||||
$this->clientError(
|
|
||||||
// TRANS: Client error. POST is a HTTP command. It should not be translated.
|
|
||||||
_('This method requires a POST.'),
|
|
||||||
400,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array($this->format, array('xml', 'json'))) {
|
if (!in_array($this->format, array('xml', 'json'))) {
|
||||||
$this->clientError(
|
$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.
|
||||||
_('API method not found.'),
|
_('API method not found.'),
|
||||||
404,
|
404
|
||||||
$this->format
|
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->other)) {
|
if (!$this->other instanceof Profile) {
|
||||||
$this->clientError(
|
$this->clientError(
|
||||||
// TRANS: Client error displayed when trying to unfollow a user that cannot be found.
|
// TRANS: Client error displayed when trying to unfollow a user that cannot be found.
|
||||||
_('Could not unfollow user: User not found.'),
|
_('Could not unfollow user: User not found.'),
|
||||||
403,
|
403
|
||||||
$this->format
|
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow unsubscribing from yourself!
|
// Don't allow unsubscribing from yourself!
|
||||||
|
|
||||||
if ($this->user->id == $this->other->id) {
|
if ($this->scoped->id == $this->other->id) {
|
||||||
$this->clientError(
|
$this->clientError(
|
||||||
// TRANS: Client error displayed when trying to unfollow self.
|
// TRANS: Client error displayed when trying to unfollow self.
|
||||||
_("You cannot unfollow yourself."),
|
_("You cannot unfollow yourself."),
|
||||||
403,
|
403
|
||||||
$this->format
|
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// throws an exception on error
|
// throws an exception on error
|
||||||
Subscription::cancel($this->user->getProfile(), $this->other);
|
Subscription::cancel($this->scoped, $this->other);
|
||||||
|
|
||||||
$this->initDocument($this->format);
|
$this->initDocument($this->format);
|
||||||
$this->showProfile($this->other, $this->format);
|
$this->showProfile($this->other, $this->format);
|
||||||
|
|||||||
@@ -29,9 +29,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the existence of friendship between two users. Will return true if
|
* Tests for the existence of friendship between two users. Will return true if
|
||||||
@@ -57,7 +55,7 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
protected function prepare(array $args=array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -72,22 +70,18 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* Check the format and show the user info
|
* Check the format and show the user info
|
||||||
*
|
*
|
||||||
* @param array $args $_REQUEST data (unused)
|
|
||||||
*
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
protected function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if (empty($this->profile_a) || empty($this->profile_b)) {
|
if (empty($this->profile_a) || empty($this->profile_b)) {
|
||||||
$this->clientError(
|
$this->clientError(
|
||||||
// TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
|
// TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
|
||||||
_('Two valid IDs or nick names must be supplied.'),
|
_('Two valid IDs or nick names must be supplied.'),
|
||||||
400,
|
400
|
||||||
$this->format
|
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = Subscription::exists($this->profile_a, $this->profile_b);
|
$result = Subscription::exists($this->profile_a, $this->profile_b);
|
||||||
|
|||||||
@@ -29,9 +29,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Outputs detailed information about the relationship between two users
|
* Outputs detailed information about the relationship between two users
|
||||||
@@ -56,7 +54,7 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
|
|||||||
*
|
*
|
||||||
* @return boolean success flag
|
* @return boolean success flag
|
||||||
*/
|
*/
|
||||||
function prepare($args)
|
protected function prepare(array $args=array())
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@@ -109,13 +107,11 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
|
|||||||
*
|
*
|
||||||
* Check the format and show the user info
|
* Check the format and show the user info
|
||||||
*
|
*
|
||||||
* @param array $args $_REQUEST data (unused)
|
|
||||||
*
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
protected function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
|
|
||||||
if (!in_array($this->format, array('xml', 'json'))) {
|
if (!in_array($this->format, array('xml', 'json'))) {
|
||||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||||
|
|||||||
@@ -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.
|
||||||
_('API method not found.'),
|
throw new ClientException(_('API method not found.'), 404);
|
||||||
404,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,11 +115,10 @@ class ApiListMembershipsAction extends ApiBareAuthAction
|
|||||||
|
|
||||||
function getLists()
|
function getLists()
|
||||||
{
|
{
|
||||||
$profile = $this->target;
|
$fn = array($this->target, 'getOtherTags');
|
||||||
$fn = array($profile, 'getOtherTags');
|
|
||||||
|
|
||||||
# 20 lists
|
# 20 lists
|
||||||
list($this->lists, $this->next_cursor, $this->prev_cursor) =
|
list($this->lists, $this->next_cursor, $this->prev_cursor) =
|
||||||
Profile_list::getAtCursor($fn, array($this->auth_user), $this->cursor, 20);
|
Profile_list::getAtCursor($fn, array($this->scoped), $this->cursor, 20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ class ApiListsAction extends ApiBareAuthAction
|
|||||||
|
|
||||||
list($this->lists,
|
list($this->lists,
|
||||||
$this->next_cursor,
|
$this->next_cursor,
|
||||||
$this->prev_cursor) = Profile_list::getAtCursor($fn, array($this->auth_user), $cursor, $count);
|
$this->prev_cursor) = Profile_list::getAtCursor($fn, array($this->scoped), $cursor, $count);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isReadOnly($args)
|
function isReadOnly($args)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload an image via the API. Returns a shortened URL for the image
|
* Upload an image via the API. Returns a shortened URL for the image
|
||||||
* to the user.
|
* to the user. Apparently modelled after a former Twitpic API.
|
||||||
*
|
*
|
||||||
* @category API
|
* @category API
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
@@ -42,17 +42,20 @@ class ApiMediaUploadAction extends ApiAuthAction
|
|||||||
{
|
{
|
||||||
protected $needPost = true;
|
protected $needPost = true;
|
||||||
|
|
||||||
/**
|
protected function prepare(array $args=array())
|
||||||
* Handle the request
|
{
|
||||||
*
|
parent::prepare($args);
|
||||||
* Grab the file from the 'media' param, then store, and shorten
|
|
||||||
*
|
// fallback to xml for older clients etc
|
||||||
* @todo Upload throttle!
|
if (empty($this->format)) {
|
||||||
*
|
$this->format = 'xml';
|
||||||
* @param array $args $_REQUEST data (unused)
|
}
|
||||||
*
|
if (!in_array($this->format, ['json', 'xml'])) {
|
||||||
* @return void
|
throw new ClientException('This API call does not support the format '._ve($this->format));
|
||||||
*/
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected function handle()
|
protected function handle()
|
||||||
{
|
{
|
||||||
parent::handle();
|
parent::handle();
|
||||||
@@ -69,14 +72,31 @@ class ApiMediaUploadAction extends ApiAuthAction
|
|||||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||||
intval($_SERVER['CONTENT_LENGTH']));
|
intval($_SERVER['CONTENT_LENGTH']));
|
||||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
throw new ClientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||||
}
|
}
|
||||||
|
|
||||||
// we could catch "NoUploadedMediaException" as "no media uploaded", but here we _always_ want an upload
|
try {
|
||||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||||
|
} catch (NoUploadedMediaException $e) {
|
||||||
|
common_debug('No media file was uploaded to the _FILES array');
|
||||||
|
$fh = tmpfile();
|
||||||
|
if ($this->arg('media')) {
|
||||||
|
common_debug('Found media parameter which we hope contains a media file!');
|
||||||
|
fwrite($fh, $this->arg('media'));
|
||||||
|
} elseif ($this->arg('media_data')) {
|
||||||
|
common_debug('Found media_data parameter which we hope contains a base64-encoded media file!');
|
||||||
|
fwrite($fh, base64_decode($this->arg('media_data')));
|
||||||
|
} else {
|
||||||
|
common_debug('No media|media_data POST parameter was supplied');
|
||||||
|
fclose($fh);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
common_debug('MediaFile importing the uploaded file with fromFilehandle');
|
||||||
|
$upload = MediaFile::fromFilehandle($fh, $this->scoped);
|
||||||
|
}
|
||||||
|
|
||||||
|
common_debug('MediaFile completed and saved us fileRecord with id=='._ve($upload->fileRecord->id));
|
||||||
// Thumbnails will be generated/cached on demand when accessed (such as with /attachment/:id/thumbnail)
|
// Thumbnails will be generated/cached on demand when accessed (such as with /attachment/:id/thumbnail)
|
||||||
|
|
||||||
$this->showResponse($upload);
|
$this->showResponse($upload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,14 +108,61 @@ class ApiMediaUploadAction extends ApiAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function showResponse(MediaFile $upload)
|
protected function showResponse(MediaFile $upload)
|
||||||
{
|
{
|
||||||
$this->initDocument();
|
$this->initDocument($this->format);
|
||||||
$this->elementStart('rsp', array('stat' => 'ok'));
|
switch ($this->format) {
|
||||||
|
case 'json':
|
||||||
|
return $this->showResponseJson($upload);
|
||||||
|
case 'xml':
|
||||||
|
return $this->showResponseXml($upload);
|
||||||
|
default:
|
||||||
|
throw new ClientException('This API call does not support the format '._ve($this->format));
|
||||||
|
}
|
||||||
|
$this->endDocument($this->format);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function showResponseJson(MediaFile $upload)
|
||||||
|
{
|
||||||
|
$enc = $upload->fileRecord->getEnclosure();
|
||||||
|
|
||||||
|
// note that we use media_id instead of mediaid which XML users might've gotten used to (nowadays we service media_id in both!)
|
||||||
|
$output = [
|
||||||
|
'media_id' => $upload->fileRecord->id,
|
||||||
|
'media_id_string' => (string)$upload->fileRecord->id,
|
||||||
|
'media_url' => $upload->shortUrl(),
|
||||||
|
'size' => $upload->fileRecord->size,
|
||||||
|
];
|
||||||
|
if (common_get_mime_media($enc->mimetype) === 'image') {
|
||||||
|
$output['image'] = [
|
||||||
|
'w' => $enc->width,
|
||||||
|
'h' => $enc->height,
|
||||||
|
'image_type' => $enc->mimetype,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
print json_encode($output);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function showResponseXml(MediaFile $upload)
|
||||||
|
{
|
||||||
|
$this->elementStart('rsp', array('stat' => 'ok', 'xmlns:atom'=>Activity::ATOM));
|
||||||
$this->element('mediaid', null, $upload->fileRecord->id);
|
$this->element('mediaid', null, $upload->fileRecord->id);
|
||||||
$this->element('mediaurl', null, $upload->shortUrl());
|
$this->element('mediaurl', null, $upload->shortUrl());
|
||||||
|
$this->element('media_url', null, $upload->shortUrl());
|
||||||
|
$this->element('size', null, $upload->fileRecord->size);
|
||||||
|
|
||||||
|
$enclosure = $upload->fileRecord->getEnclosure();
|
||||||
|
$this->element('atom:link', array('rel' => 'enclosure',
|
||||||
|
'href' => $enclosure->url,
|
||||||
|
'type' => $enclosure->mimetype));
|
||||||
|
|
||||||
|
// Twitter specific metadata expected in response since Twitter's Media upload API v1.1 (even though Twitter doesn't use XML)
|
||||||
|
$this->element('media_id', null, $upload->fileRecord->id);
|
||||||
|
$this->element('media_id_string', null, (string)$upload->fileRecord->id);
|
||||||
|
if (common_get_mime_media($enclosure->mimetype) === 'image') {
|
||||||
|
$this->element('image', ['w'=>$enclosure->width, 'h'=>$enclosure->height, 'image_type'=>$enclosure->mimetype]);
|
||||||
|
}
|
||||||
$this->elementEnd('rsp');
|
$this->elementEnd('rsp');
|
||||||
$this->endDocument();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,9 +170,16 @@ class ApiMediaUploadAction extends ApiAuthAction
|
|||||||
*
|
*
|
||||||
* @param String $msg an error message
|
* @param String $msg an error message
|
||||||
*/
|
*/
|
||||||
function clientError($msg)
|
function clientError($msg, $code=400, $format=null)
|
||||||
{
|
{
|
||||||
$this->initDocument();
|
$this->initDocument($this->format);
|
||||||
|
switch ($this->format) {
|
||||||
|
case 'json':
|
||||||
|
$error = ['errors' => array()];
|
||||||
|
$error['errors'][] = ['message'=>$msg, 'code'=>131];
|
||||||
|
print json_encode($error);
|
||||||
|
break;
|
||||||
|
case 'xml':
|
||||||
$this->elementStart('rsp', array('stat' => 'fail'));
|
$this->elementStart('rsp', array('stat' => 'fail'));
|
||||||
|
|
||||||
// @todo add in error code
|
// @todo add in error code
|
||||||
@@ -113,6 +187,9 @@ class ApiMediaUploadAction extends ApiAuthAction
|
|||||||
|
|
||||||
$this->element('err', $errAttr, null);
|
$this->element('err', $errAttr, null);
|
||||||
$this->elementEnd('rsp');
|
$this->elementEnd('rsp');
|
||||||
$this->endDocument();
|
break;
|
||||||
|
}
|
||||||
|
$this->endDocument($this->format);
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
@@ -327,7 +327,7 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
|
|||||||
'rel' => 'alternate',
|
'rel' => 'alternate',
|
||||||
'href' => $nurl));
|
'href' => $nurl));
|
||||||
$this->element('title', null, common_xml_safe_str(trim($notice->content)));
|
$this->element('title', null, common_xml_safe_str(trim($notice->content)));
|
||||||
$this->element('content', array('type' => 'html'), $notice->rendered);
|
$this->element('content', array('type' => 'html'), $notice->getRendered());
|
||||||
$this->element('updated', null, common_date_w3dtf($notice->created));
|
$this->element('updated', null, common_date_w3dtf($notice->created));
|
||||||
$this->element('link', array('type' => 'image/png',
|
$this->element('link', array('type' => 'image/png',
|
||||||
// XXX: Twitter uses rel="image" (not valid)
|
// XXX: Twitter uses rel="image" (not valid)
|
||||||
@@ -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 = '<a href="'
|
|
||||||
. htmlspecialchars($ns->url)
|
|
||||||
. '" rel="nofollow">'
|
|
||||||
. htmlspecialchars($ns->name)
|
|
||||||
. '</a>';
|
|
||||||
} else {
|
|
||||||
$source = $ns->code;
|
$source = $ns->code;
|
||||||
|
if (!empty($ns->url)) {
|
||||||
|
$source_link = $ns->url;
|
||||||
|
if (!empty($ns->name)) {
|
||||||
|
$source = $ns->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->element("twitter:source", null, $source);
|
$this->element("twitter:source", 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->delete();
|
|
||||||
Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
|
|
||||||
}
|
}
|
||||||
$this->showNotice();
|
$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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -74,16 +74,21 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
|||||||
|
|
||||||
$this->notice_id = (int)$this->trimmed('id');
|
$this->notice_id = (int)$this->trimmed('id');
|
||||||
|
|
||||||
$this->notice = Notice::getKV('id', $this->notice_id);
|
$this->notice = null;
|
||||||
if (!$this->notice instanceof Notice) {
|
try {
|
||||||
$deleted = Deleted_notice::getKV('id', $this->notice_id);
|
$this->notice = Notice::getByID($this->notice_id);
|
||||||
if ($deleted instanceof Deleted_notice) {
|
} catch (NoResultException $e) {
|
||||||
|
// No such notice was found, maybe it was deleted?
|
||||||
|
$deleted = null;
|
||||||
|
Event::handle('IsNoticeDeleted', array($this->notice_id, &$deleted));
|
||||||
|
if ($deleted === true) {
|
||||||
// TRANS: Client error displayed trying to show a deleted notice.
|
// TRANS: Client error displayed trying to show a deleted notice.
|
||||||
$this->clientError(_('Notice deleted.'), 410);
|
throw new ClientException(_('Notice deleted.'), 410);
|
||||||
}
|
}
|
||||||
// TRANS: Client error displayed trying to show a non-existing notice.
|
// TRANS: Client error displayed trying to show a non-existing notice.
|
||||||
$this->clientError(_('No such notice.'), 404);
|
throw new ClientException(_('No such notice.'), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->notice->inScope($this->scoped)) {
|
if (!$this->notice->inScope($this->scoped)) {
|
||||||
// TRANS: Client exception thrown when trying a view a notice the user has no access to.
|
// TRANS: Client exception thrown when trying a view a notice the user has no access to.
|
||||||
throw new ClientException(_('Access restricted.'), 403);
|
throw new ClientException(_('Access restricted.'), 403);
|
||||||
@@ -128,7 +133,6 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
|||||||
*/
|
*/
|
||||||
function showNotice()
|
function showNotice()
|
||||||
{
|
{
|
||||||
if (!empty($this->notice)) {
|
|
||||||
switch ($this->format) {
|
switch ($this->format) {
|
||||||
case 'xml':
|
case 'xml':
|
||||||
$this->showSingleXmlStatus($this->notice);
|
$this->showSingleXmlStatus($this->notice);
|
||||||
@@ -144,28 +148,6 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
|||||||
// TRANS: %s is the requested output format.
|
// TRANS: %s is the requested output format.
|
||||||
throw new Exception(sprintf(_("Unsupported format: %s."), $this->format));
|
throw new Exception(sprintf(_("Unsupported format: %s."), $this->format));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// XXX: Twitter just sets a 404 header and doens't bother
|
|
||||||
// to return an err msg
|
|
||||||
|
|
||||||
$deleted = Deleted_notice::getKV($this->notice_id);
|
|
||||||
|
|
||||||
if (!empty($deleted)) {
|
|
||||||
$this->clientError(
|
|
||||||
// TRANS: Client error displayed requesting a deleted status.
|
|
||||||
_('Status deleted.'),
|
|
||||||
410,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->clientError(
|
|
||||||
// TRANS: Client error displayed requesting a status with an invalid ID.
|
|
||||||
_('No status with that ID found.'),
|
|
||||||
404,
|
|
||||||
$this->format
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,13 +170,9 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
|||||||
*/
|
*/
|
||||||
function lastModified()
|
function lastModified()
|
||||||
{
|
{
|
||||||
if (!empty($this->notice)) {
|
|
||||||
return strtotime($this->notice->created);
|
return strtotime($this->notice->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An entity tag for this notice
|
* An entity tag for this notice
|
||||||
*
|
*
|
||||||
@@ -205,8 +183,6 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
|||||||
*/
|
*/
|
||||||
function etag()
|
function etag()
|
||||||
{
|
{
|
||||||
if (!empty($this->notice)) {
|
|
||||||
|
|
||||||
return '"' . implode(
|
return '"' . implode(
|
||||||
':',
|
':',
|
||||||
array($this->arg('action'),
|
array($this->arg('action'),
|
||||||
@@ -218,9 +194,6 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
|||||||
. '"';
|
. '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteNotice()
|
function deleteNotice()
|
||||||
{
|
{
|
||||||
if ($this->format != 'atom') {
|
if ($this->format != 'atom') {
|
||||||
@@ -236,7 +209,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartDeleteOwnNotice', array($this->auth_user, $this->notice))) {
|
if (Event::handle('StartDeleteOwnNotice', array($this->auth_user, $this->notice))) {
|
||||||
$this->notice->delete();
|
$this->notice->deleteAs($this->scoped);
|
||||||
Event::handle('EndDeleteOwnNotice', array($this->auth_user, $this->notice));
|
Event::handle('EndDeleteOwnNotice', array($this->auth_user, $this->notice));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -152,6 +152,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
var $in_reply_to_status_id = null;
|
var $in_reply_to_status_id = null;
|
||||||
var $lat = null;
|
var $lat = null;
|
||||||
var $lon = null;
|
var $lon = null;
|
||||||
|
var $media_ids = array(); // file_id in the keys
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take arguments for running
|
* Take arguments for running
|
||||||
@@ -167,6 +168,19 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
$this->status = $this->trimmed('status');
|
$this->status = $this->trimmed('status');
|
||||||
$this->lat = $this->trimmed('lat');
|
$this->lat = $this->trimmed('lat');
|
||||||
$this->lon = $this->trimmed('long');
|
$this->lon = $this->trimmed('long');
|
||||||
|
$matches = array();
|
||||||
|
common_debug(get_called_class().': media_ids=='._ve($this->trimmed('media_ids')));
|
||||||
|
if (preg_match_all('/\d+/', $this->trimmed('media_ids'), $matches) !== false) {
|
||||||
|
foreach (array_unique($matches[0]) as $match) {
|
||||||
|
try {
|
||||||
|
$this->media_ids[$match] = File::getByID($match);
|
||||||
|
} catch (EmptyPkeyValueException $e) {
|
||||||
|
// got a zero from the client, at least Twidere does this on occasion
|
||||||
|
} catch (NoResultException $e) {
|
||||||
|
// File ID was not found. Do we abort and report to the client?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->in_reply_to_status_id
|
$this->in_reply_to_status_id
|
||||||
= intval($this->trimmed('in_reply_to_status_id'));
|
= intval($this->trimmed('in_reply_to_status_id'));
|
||||||
@@ -211,7 +225,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
$this->clientError(_('No such user.'), 404);
|
$this->clientError(_('No such user.'), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do not call shortenlinks until the whole notice has been build */
|
/* Do not call shortenLinks until the whole notice has been build */
|
||||||
|
|
||||||
// Check for commands
|
// Check for commands
|
||||||
|
|
||||||
@@ -244,17 +258,24 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach(array_keys($this->media_ids) as $media_id) {
|
||||||
|
// FIXME: Validation on this... Worst case is that if someone sends bad media_ids then
|
||||||
|
// we'll fill the notice with non-working links, so no real harm, done, but let's fix.
|
||||||
|
// The File objects are in the array, so we could get URLs from them directly.
|
||||||
|
$this->status .= ' ' . common_local_url('attachment', array('attachment' => $media_id));
|
||||||
|
}
|
||||||
|
|
||||||
$upload = null;
|
$upload = null;
|
||||||
try {
|
try {
|
||||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||||
$this->status .= ' ' . $upload->shortUrl();
|
$this->status .= ' ' . $upload->shortUrl();
|
||||||
/* Do not call shortenlinks until the whole notice has been build */
|
/* Do not call shortenLinks until the whole notice has been build */
|
||||||
} catch (NoUploadedMediaException $e) {
|
} catch (NoUploadedMediaException $e) {
|
||||||
// There was no uploaded media for us today.
|
// There was no uploaded media for us today.
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do call shortenlinks here & check notice length since notice is about to be saved & sent */
|
/* Do call shortenlinks here & check notice length since notice is about to be saved & sent */
|
||||||
$status_shortened = $this->auth_user->shortenlinks($this->status);
|
$status_shortened = $this->auth_user->shortenLinks($this->status);
|
||||||
|
|
||||||
if (Notice::contentTooLong($status_shortened)) {
|
if (Notice::contentTooLong($status_shortened)) {
|
||||||
if ($upload instanceof MediaFile) {
|
if ($upload instanceof MediaFile) {
|
||||||
@@ -318,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/>
|
||||||
|
|||||||
@@ -51,19 +51,10 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
|||||||
{
|
{
|
||||||
var $notices = null;
|
var $notices = 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);
|
||||||
|
|
||||||
common_debug("apitimelinetag prepare()");
|
|
||||||
|
|
||||||
$this->tag = $this->arg('tag');
|
$this->tag = $this->arg('tag');
|
||||||
$this->notices = $this->getNotices();
|
$this->notices = $this->getNotices();
|
||||||
|
|
||||||
@@ -79,9 +70,9 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle($args)
|
protected function handle()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle();
|
||||||
$this->showTimeline();
|
$this->showTimeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,21 +163,12 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
|||||||
*/
|
*/
|
||||||
function getNotices()
|
function getNotices()
|
||||||
{
|
{
|
||||||
$notices = array();
|
$notice = Notice_tag::getStream($this->tag)->getNotices(($this->page - 1) * $this->count,
|
||||||
|
|
||||||
$notice = Notice_tag::getStream(
|
|
||||||
$this->tag,
|
|
||||||
($this->page - 1) * $this->count,
|
|
||||||
$this->count + 1,
|
$this->count + 1,
|
||||||
$this->since_id,
|
$this->since_id,
|
||||||
$this->max_id
|
$this->max_id);
|
||||||
);
|
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
return $notice->fetchAll();
|
||||||
$notices[] = clone($notice);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $notices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,208 +57,9 @@ if (!defined('STATUSNET')) {
|
|||||||
*/
|
*/
|
||||||
class ApiTimelineUserAction extends ApiBareAuthAction
|
class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
{
|
{
|
||||||
var $notices = null;
|
public $notices = null;
|
||||||
|
|
||||||
var $next_id = null;
|
public $next_id = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Take arguments for running
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST args
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
protected function prepare(array $args=array())
|
|
||||||
{
|
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
|
||||||
|
|
||||||
if (!($this->target instanceof Profile)) {
|
|
||||||
// TRANS: Client error displayed requesting most recent notices for a non-existing user.
|
|
||||||
$this->clientError(_('No such user.'), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->notices = $this->getNotices();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the request
|
|
||||||
*
|
|
||||||
* Just show the notices
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function handle()
|
|
||||||
{
|
|
||||||
parent::handle();
|
|
||||||
|
|
||||||
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->auth_user);
|
|
||||||
|
|
||||||
$link = common_local_url(
|
|
||||||
'showstream',
|
|
||||||
array('nickname' => $this->target->nickname)
|
|
||||||
);
|
|
||||||
|
|
||||||
$self = $this->getSelfUri();
|
|
||||||
|
|
||||||
// FriendFeed's SUP protocol
|
|
||||||
// Also added RSS and Atom feeds
|
|
||||||
|
|
||||||
$suplink = common_local_url('sup', null, null, $this->target->id);
|
|
||||||
header('X-SUP-ID: ' . $suplink);
|
|
||||||
|
|
||||||
|
|
||||||
// paging links
|
|
||||||
$nextUrl = !empty($this->next_id)
|
|
||||||
? common_local_url('ApiTimelineUser',
|
|
||||||
array('format' => $this->format,
|
|
||||||
'id' => $this->target->id),
|
|
||||||
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->id),
|
|
||||||
$prevExtra);
|
|
||||||
$firstUrl = common_local_url('ApiTimelineUser',
|
|
||||||
array('format' => $this->format,
|
|
||||||
'id' => $this->target->id));
|
|
||||||
|
|
||||||
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->auth_user);
|
|
||||||
$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
|
|
||||||
*
|
|
||||||
* @return array notices
|
|
||||||
*/
|
|
||||||
function getNotices()
|
|
||||||
{
|
|
||||||
$notices = array();
|
|
||||||
|
|
||||||
$notice = $this->target->getNotices(($this->page-1) * $this->count,
|
|
||||||
$this->count + 1,
|
|
||||||
$this->since_id,
|
|
||||||
$this->max_id,
|
|
||||||
$this->scoped);
|
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
|
||||||
if (count($notices) < $this->count) {
|
|
||||||
$notices[] = clone($notice);
|
|
||||||
} else {
|
|
||||||
$this->next_id = $notice->id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $notices;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
|
* We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
|
||||||
@@ -268,7 +69,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
* @return boolean true
|
* @return boolean true
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function isReadOnly($args)
|
public function isReadOnly($args)
|
||||||
{
|
{
|
||||||
return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
||||||
}
|
}
|
||||||
@@ -278,7 +79,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
*
|
*
|
||||||
* @return string datestamp of the latest notice in the stream
|
* @return string datestamp of the latest notice in the stream
|
||||||
*/
|
*/
|
||||||
function lastModified()
|
public function lastModified()
|
||||||
{
|
{
|
||||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||||
return strtotime($this->notices[0]->created);
|
return strtotime($this->notices[0]->created);
|
||||||
@@ -295,7 +96,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
*
|
*
|
||||||
* @return string etag
|
* @return string etag
|
||||||
*/
|
*/
|
||||||
function etag()
|
public function etag()
|
||||||
{
|
{
|
||||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||||
$last = count($this->notices) - 1;
|
$last = count($this->notices) - 1;
|
||||||
@@ -303,9 +104,9 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
return '"' . implode(
|
return '"' . implode(
|
||||||
':',
|
':',
|
||||||
array($this->arg('action'),
|
array($this->arg('action'),
|
||||||
common_user_cache_hash($this->auth_user),
|
common_user_cache_hash($this->scoped),
|
||||||
common_language(),
|
common_language(),
|
||||||
$this->target->id,
|
$this->target->getID(),
|
||||||
strtotime($this->notices[0]->created),
|
strtotime($this->notices[0]->created),
|
||||||
strtotime($this->notices[$last]->created))
|
strtotime($this->notices[$last]->created))
|
||||||
)
|
)
|
||||||
@@ -315,12 +116,90 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePost()
|
/**
|
||||||
|
* Take arguments for running
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST args
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
* @throws AuthorizationException
|
||||||
|
* @throws ClientException
|
||||||
|
*/
|
||||||
|
protected function prepare(array $args = [])
|
||||||
{
|
{
|
||||||
if (empty($this->auth_user) ||
|
parent::prepare($args);
|
||||||
$this->auth_user->id != $this->target->id) {
|
|
||||||
|
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||||
|
|
||||||
|
if (!($this->target instanceof Profile)) {
|
||||||
|
// TRANS: Client error displayed requesting most recent notices for a non-existing user.
|
||||||
|
$this->clientError(_('No such user.'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->target->isLocal()) {
|
||||||
|
$this->serverError(_('Remote user timelines are not available here yet.'), 501);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->notices = $this->getNotices();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get notices
|
||||||
|
*
|
||||||
|
* @return array notices
|
||||||
|
*/
|
||||||
|
public function getNotices()
|
||||||
|
{
|
||||||
|
$notices = [];
|
||||||
|
|
||||||
|
$notice = $this->target->getNotices(
|
||||||
|
($this->page - 1) * $this->count,
|
||||||
|
$this->count + 1,
|
||||||
|
$this->since_id,
|
||||||
|
$this->max_id,
|
||||||
|
$this->scoped
|
||||||
|
);
|
||||||
|
|
||||||
|
while ($notice->fetch()) {
|
||||||
|
if (count($notices) < $this->count) {
|
||||||
|
$notices[] = clone($notice);
|
||||||
|
} else {
|
||||||
|
$this->next_id = $notice->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $notices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the request
|
||||||
|
*
|
||||||
|
* Just show the notices
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws ClientException
|
||||||
|
* @throws ServerException
|
||||||
|
*/
|
||||||
|
protected function handle()
|
||||||
|
{
|
||||||
|
parent::handle();
|
||||||
|
|
||||||
|
if ($this->isPost()) {
|
||||||
|
$this->handlePost();
|
||||||
|
} else {
|
||||||
|
$this->showTimeline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handlePost()
|
||||||
|
{
|
||||||
|
if (!$this->scoped instanceof Profile ||
|
||||||
|
!$this->target->sameAs($this->scoped)) {
|
||||||
// TRANS: Client error displayed trying to add a notice to another user's timeline.
|
// 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.'));
|
$this->clientError(_('Only the user can add to their own timeline.'), 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only handle posts for Atom
|
// Only handle posts for Atom
|
||||||
@@ -352,165 +231,179 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||||||
|
|
||||||
$activity = new Activity($dom->documentElement);
|
$activity = new Activity($dom->documentElement);
|
||||||
|
|
||||||
$saved = null;
|
common_debug('AtomPub: Ignoring right now, but this POST was made to collection: ' . $activity->id);
|
||||||
|
|
||||||
if (Event::handle('StartAtomPubNewActivity', array(&$activity, $this->target->getUser(), &$saved))) {
|
// Reset activity data so we can handle it in the same functions as with OStatus
|
||||||
if ($activity->verb != ActivityVerb::POST) {
|
// because we don't let clients set their own UUIDs... Not sure what AtomPub thinks
|
||||||
|
// about that though.
|
||||||
|
$activity->id = null;
|
||||||
|
$activity->actor = null; // not used anyway, we use $this->target
|
||||||
|
$activity->objects[0]->id = null;
|
||||||
|
|
||||||
|
$stored = null;
|
||||||
|
if (Event::handle('StartAtomPubNewActivity', array($activity, $this->target, &$stored))) {
|
||||||
// TRANS: Client error displayed when not using the POST verb. Do not translate POST.
|
// TRANS: Client error displayed when not using the POST verb. Do not translate POST.
|
||||||
$this->clientError(_('Can only handle POST activities.'));
|
throw new ClientException(_('Could not handle this Atom Activity.'));
|
||||||
}
|
}
|
||||||
|
if (!$stored instanceof Notice) {
|
||||||
$note = $activity->objects[0];
|
throw new ServerException('Server did not create a Notice object from handled AtomPub activity.');
|
||||||
|
|
||||||
if (!in_array($note->type, array(ActivityObject::NOTE,
|
|
||||||
ActivityObject::BLOGENTRY,
|
|
||||||
ActivityObject::STATUS))) {
|
|
||||||
// TRANS: Client error displayed when using an unsupported activity object type.
|
|
||||||
// TRANS: %s is the unsupported activity object type.
|
|
||||||
$this->clientError(sprintf(_('Cannot handle activity object type "%s".'),
|
|
||||||
$note->type));
|
|
||||||
}
|
}
|
||||||
|
Event::handle('EndAtomPubNewActivity', array($activity, $this->target, $stored));
|
||||||
|
|
||||||
$saved = $this->postNote($activity);
|
|
||||||
|
|
||||||
Event::handle('EndAtomPubNewActivity', array($activity, $this->target->getUser(), $saved));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($saved)) {
|
|
||||||
header('HTTP/1.1 201 Created');
|
header('HTTP/1.1 201 Created');
|
||||||
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $saved->id,
|
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $stored->getID(),
|
||||||
'format' => 'atom')));
|
'format' => 'atom')));
|
||||||
$this->showSingleAtomStatus($saved);
|
$this->showSingleAtomStatus($stored);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function postNote($activity)
|
/**
|
||||||
|
* Show the timeline of notices
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws ClientException
|
||||||
|
* @throws ServerException
|
||||||
|
* @throws UserNoProfileException
|
||||||
|
*/
|
||||||
|
public function showTimeline()
|
||||||
{
|
{
|
||||||
$note = $activity->objects[0];
|
// We'll use the shared params from the Atom stub
|
||||||
|
// for other feed types.
|
||||||
|
$atom = new AtomUserNoticeFeed($this->target->getUser(), $this->scoped);
|
||||||
|
|
||||||
// Use summary as fallback for content
|
$link = common_local_url(
|
||||||
|
'showstream',
|
||||||
|
array('nickname' => $this->target->getNickname())
|
||||||
|
);
|
||||||
|
|
||||||
if (!empty($note->content)) {
|
$self = $this->getSelfUri();
|
||||||
$sourceContent = $note->content;
|
|
||||||
} else if (!empty($note->summary)) {
|
// FriendFeed's SUP protocol
|
||||||
$sourceContent = $note->summary;
|
// Also added RSS and Atom feeds
|
||||||
} else if (!empty($note->title)) {
|
|
||||||
$sourceContent = $note->title;
|
$suplink = common_local_url('sup', null, null, $this->target->getID());
|
||||||
} else {
|
header('X-SUP-ID: ' . $suplink);
|
||||||
// @fixme fetch from $sourceUrl?
|
|
||||||
// TRANS: Client error displayed when posting a notice without content through the API.
|
|
||||||
// TRANS: %d is the notice ID (number).
|
// paging links
|
||||||
$this->clientError(sprintf(_('No content for notice %d.'), $note->id));
|
$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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get (safe!) HTML and text versions of the content
|
$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())
|
||||||
|
);
|
||||||
|
|
||||||
$rendered = $this->purify($sourceContent);
|
switch ($this->format) {
|
||||||
$content = common_strip_html($rendered);
|
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');
|
||||||
|
|
||||||
$shortened = $this->auth_user->shortenLinks($content);
|
$atom->setId($self);
|
||||||
|
$atom->setSelfLink($self);
|
||||||
|
|
||||||
$options = array('is_local' => Notice::LOCAL_PUBLIC,
|
// Add navigation links: next, prev, first
|
||||||
'rendered' => $rendered,
|
// Note: we use IDs rather than pages for navigation; page boundaries
|
||||||
'replies' => array(),
|
// change too quickly!
|
||||||
'groups' => array(),
|
|
||||||
'tags' => array(),
|
|
||||||
'urls' => array());
|
|
||||||
|
|
||||||
// accept remote URI (not necessarily a good idea)
|
if (!empty($this->next_id)) {
|
||||||
|
$atom->addLink(
|
||||||
common_debug("Note ID is {$note->id}");
|
$nextUrl,
|
||||||
|
array('rel' => 'next',
|
||||||
if (!empty($note->id)) {
|
'type' => 'application/atom+xml')
|
||||||
$notice = Notice::getKV('uri', trim($note->id));
|
);
|
||||||
|
|
||||||
if (!empty($notice)) {
|
|
||||||
// TRANS: Client error displayed when using another format than AtomPub.
|
|
||||||
// TRANS: %s is the notice URI.
|
|
||||||
$this->clientError(sprintf(_('Notice with URI "%s" already exists.'), $note->id));
|
|
||||||
}
|
|
||||||
common_log(LOG_NOTICE, "Saving client-supplied notice URI '$note->id'");
|
|
||||||
$options['uri'] = $note->id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// accept remote create time (also maybe not such a good idea)
|
if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
|
||||||
|
$atom->addLink(
|
||||||
if (!empty($activity->time)) {
|
$prevUrl,
|
||||||
common_log(LOG_NOTICE, "Saving client-supplied create time {$activity->time}");
|
array('rel' => 'prev',
|
||||||
$options['created'] = common_sql_date($activity->time);
|
'type' => 'application/atom+xml')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for optional attributes...
|
if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
|
||||||
|
$atom->addLink(
|
||||||
if ($activity->context instanceof ActivityContext) {
|
$firstUrl,
|
||||||
|
array('rel' => 'first',
|
||||||
foreach ($activity->context->attention as $uri=>$type) {
|
'type' => 'application/atom+xml')
|
||||||
try {
|
);
|
||||||
$profile = Profile::fromUri($uri);
|
|
||||||
if ($profile->isGroup()) {
|
|
||||||
$options['groups'][] = $profile->id;
|
|
||||||
} else {
|
|
||||||
$options['replies'][] = $uri;
|
|
||||||
}
|
|
||||||
} catch (UnknownUriException $e) {
|
|
||||||
common_log(LOG_WARNING, sprintf('AtomPub post with unknown attention URI %s', $uri));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maintain direct reply associations
|
$atom->addEntryFromNotices($this->notices);
|
||||||
// @fixme what about conversation ID?
|
$this->raw($atom->getString());
|
||||||
|
|
||||||
if (!empty($activity->context->replyToID)) {
|
break;
|
||||||
$orig = Notice::getKV('uri',
|
case 'json':
|
||||||
$activity->context->replyToID);
|
$this->showJsonTimeline($this->notices);
|
||||||
if (!empty($orig)) {
|
break;
|
||||||
$options['reply_to'] = $orig->id;
|
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)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$location = $activity->context->location;
|
if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
|
||||||
|
$doc->addLink(
|
||||||
if ($location) {
|
$prevUrl,
|
||||||
$options['lat'] = $location->lat;
|
array('rel' => 'prev',
|
||||||
$options['lon'] = $location->lon;
|
'type' => ActivityStreamJSONDocument::CONTENT_TYPE)
|
||||||
if ($location->location_id) {
|
);
|
||||||
$options['location_ns'] = $location->location_ns;
|
|
||||||
$options['location_id'] = $location->location_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atom categories <-> hashtags
|
if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
|
||||||
|
$doc->addLink(
|
||||||
foreach ($activity->categories as $cat) {
|
$firstUrl,
|
||||||
if ($cat->term) {
|
array('rel' => 'first',
|
||||||
$term = common_canonical_tag($cat->term);
|
'type' => ActivityStreamJSONDocument::CONTENT_TYPE)
|
||||||
if ($term) {
|
);
|
||||||
$options['tags'][] = $term;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atom enclosures -> attachment URLs
|
$this->raw($doc->asString());
|
||||||
foreach ($activity->enclosures as $href) {
|
break;
|
||||||
// @fixme save these locally or....?
|
default:
|
||||||
$options['urls'][] = $href;
|
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||||
|
$this->clientError(_('API method not found.'), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$saved = Notice::saveNew($this->target->id,
|
|
||||||
$content,
|
|
||||||
'atompub', // TODO: deal with this
|
|
||||||
$options);
|
|
||||||
|
|
||||||
return $saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
function purify($content)
|
|
||||||
{
|
|
||||||
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
|
|
||||||
|
|
||||||
$config = array('safe' => 1,
|
|
||||||
'deny_attribute' => 'id,style,on*');
|
|
||||||
return htmLawed($content, $config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -230,18 +230,11 @@ class AtompubsubscriptionfeedAction extends AtompubAction
|
|||||||
$this->clientError(sprintf(_('Unknown profile %s.'), $person->id));
|
$this->clientError(sprintf(_('Unknown profile %s.'), $person->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Subscription::exists($this->_profile, $profile)) {
|
try {
|
||||||
|
$sub = Subscription::start($this->_profile, $profile);
|
||||||
|
} catch (AlreadyFulfilledException $e) {
|
||||||
// 409 Conflict
|
// 409 Conflict
|
||||||
// TRANS: Client error displayed trying to subscribe to an already subscribed profile.
|
$this->clientError($e->getMessage(), 409);
|
||||||
// TRANS: %s is the profile the user already has a subscription on.
|
|
||||||
$this->clientError(sprintf(_('Already subscribed to %s.'),
|
|
||||||
$person->id),
|
|
||||||
409);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Subscription::start($this->_profile, $profile)) {
|
|
||||||
$sub = Subscription::pkeyGet(array('subscriber' => $this->_profile->id,
|
|
||||||
'subscribed' => $profile->id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::handle('EndAtomPubNewActivity', array($activity, $sub));
|
Event::handle('EndAtomPubNewActivity', array($activity, $sub));
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class AttachmentAction extends ManagedAction
|
|||||||
{
|
{
|
||||||
if (empty($this->attachment->filename)) {
|
if (empty($this->attachment->filename)) {
|
||||||
// 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 +132,5 @@ 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
actions/attachment_download.php
Normal file
20
actions/attachment_download.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?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()
|
||||||
|
{
|
||||||
|
common_redirect($this->attachment->getUrl(), 302);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,9 +59,9 @@ class Attachment_thumbnailAction extends AttachmentAction
|
|||||||
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);
|
||||||
} catch (UseFileAsThumbnailException $e) {
|
} catch (UseFileAsThumbnailException $e) {
|
||||||
common_redirect($e->file->getUrl());
|
common_redirect($e->file->getUrl(), 302);
|
||||||
}
|
}
|
||||||
|
|
||||||
common_redirect($thumbnail->getUrl());
|
common_redirect(File_thumbnail::url($thumbnail->getFilename()), 302);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
define('MAX_ORIGINAL', 480);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload an avatar
|
* Upload an avatar
|
||||||
@@ -55,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
|
||||||
*
|
*
|
||||||
@@ -82,11 +90,11 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
/**
|
/**
|
||||||
* Content area of the page
|
* Content area of the page
|
||||||
*
|
*
|
||||||
* Shows a form for uploading an avatar.
|
* Shows a form for uploading an avatar. Currently overrides FormAction's showContent
|
||||||
|
* since we haven't made classes out of AvatarCropForm and AvatarUploadForm.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
if ($this->mode == 'crop') {
|
if ($this->mode == 'crop') {
|
||||||
@@ -98,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',
|
||||||
@@ -122,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'));
|
||||||
@@ -132,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) {
|
||||||
@@ -140,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).
|
||||||
@@ -149,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.
|
||||||
@@ -186,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',
|
||||||
@@ -217,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');
|
||||||
|
|
||||||
@@ -230,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',
|
||||||
@@ -249,51 +237,18 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function doPost()
|
||||||
* Handle a post
|
|
||||||
*
|
|
||||||
* We mux on the button name to figure out what the user actually wanted.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function handlePost()
|
|
||||||
{
|
{
|
||||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
|
||||||
// length > post_max_size in php.ini
|
|
||||||
|
|
||||||
if (empty($_FILES)
|
|
||||||
&& empty($_POST)
|
|
||||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
|
||||||
) {
|
|
||||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
|
||||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
|
||||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
|
||||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
|
||||||
intval($_SERVER['CONTENT_LENGTH']));
|
|
||||||
$this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CSRF protection
|
|
||||||
|
|
||||||
$token = $this->trimmed('token');
|
|
||||||
if (!$token || $token != common_session_token()) {
|
|
||||||
// TRANS: Client error displayed when the session token does not match or is not given.
|
|
||||||
$this->showForm(_('There was a problem with your session token. '.
|
|
||||||
'Try again, please.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Event::handle('StartAvatarSaveForm', array($this))) {
|
if (Event::handle('StartAvatarSaveForm', array($this))) {
|
||||||
if ($this->arg('upload')) {
|
if ($this->trimmed('upload')) {
|
||||||
$this->uploadAvatar();
|
return $this->uploadAvatar();
|
||||||
} else if ($this->arg('crop')) {
|
} else if ($this->trimmed('crop')) {
|
||||||
$this->cropAvatar();
|
return $this->cropAvatar();
|
||||||
} else if ($this->arg('delete')) {
|
} else if ($this->trimmed('delete')) {
|
||||||
$this->deleteAvatar();
|
return $this->deleteAvatar();
|
||||||
} else {
|
} else {
|
||||||
// TRANS: Unexpected validation error on avatar upload form.
|
// TRANS: Unexpected validation error on avatar upload form.
|
||||||
$this->showForm(_('Unexpected form submission.'));
|
throw new ClientException(_('Unexpected form submission.'));
|
||||||
}
|
}
|
||||||
Event::handle('EndAvatarSaveForm', array($this));
|
Event::handle('EndAvatarSaveForm', array($this));
|
||||||
}
|
}
|
||||||
@@ -309,21 +264,12 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function uploadAvatar()
|
function uploadAvatar()
|
||||||
{
|
{
|
||||||
try {
|
// ImageFile throws exception if something goes wrong, which we'll
|
||||||
|
// pick up and show as an error message above the form.
|
||||||
$imagefile = ImageFile::fromUpload('avatarfile');
|
$imagefile = ImageFile::fromUpload('avatarfile');
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->showForm($e->getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($imagefile === null) {
|
|
||||||
// TRANS: Validation error on avatar upload form when no file was uploaded.
|
|
||||||
$this->showForm(_('No file uploaded.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cur = common_current_user();
|
|
||||||
$type = $imagefile->preferredType();
|
$type = $imagefile->preferredType();
|
||||||
$filename = Avatar::filename($cur->id,
|
$filename = Avatar::filename($this->scoped->getID(),
|
||||||
image_type_to_extension($type),
|
image_type_to_extension($type),
|
||||||
null,
|
null,
|
||||||
'tmp'.common_timestamp());
|
'tmp'.common_timestamp());
|
||||||
@@ -344,8 +290,7 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
$this->mode = 'crop';
|
$this->mode = 'crop';
|
||||||
|
|
||||||
// TRANS: Avatar upload form instruction after uploading a file.
|
// TRANS: Avatar upload form instruction after uploading a file.
|
||||||
$this->showForm(_('Pick a square area of the image to be your avatar.'),
|
return _('Pick a square area of the image to be your avatar.');
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -357,36 +302,46 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
{
|
{
|
||||||
$filedata = $_SESSION['FILEDATA'];
|
$filedata = $_SESSION['FILEDATA'];
|
||||||
|
|
||||||
if (!$filedata) {
|
if (empty($filedata)) {
|
||||||
// TRANS: Server error displayed if an avatar upload went wrong somehow server side.
|
// TRANS: Server error displayed if an avatar upload went wrong somehow server side.
|
||||||
$this->serverError(_('Lost our file data.'));
|
throw new ServerException(_('Lost our file data.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$file_d = ($filedata['width'] > $filedata['height'])
|
$file_d = min($filedata['width'], $filedata['height']);
|
||||||
? $filedata['height'] : $filedata['width'];
|
|
||||||
|
|
||||||
$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'):$file_d;
|
$dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$file_d;
|
||||||
$dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$file_d;
|
$dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$file_d;
|
||||||
$size = intval(min($dest_w, $dest_h, MAX_ORIGINAL));
|
$size = intval(min($dest_w, $dest_h, common_config('avatar', 'maxsize')));
|
||||||
|
|
||||||
$user = common_current_user();
|
$box = array('width' => $size, 'height' => $size,
|
||||||
$profile = $user->getProfile();
|
'x' => $dest_x, 'y' => $dest_y,
|
||||||
|
'w' => $dest_w, 'h' => $dest_h);
|
||||||
|
|
||||||
$imagefile = new ImageFile($user->id, $filedata['filepath']);
|
$imagefile = new ImageFile(null, $filedata['filepath']);
|
||||||
$filename = $imagefile->resize($size, $dest_x, $dest_y, $dest_w, $dest_h);
|
$filename = Avatar::filename($this->scoped->getID(), image_type_to_extension($imagefile->preferredType()),
|
||||||
|
$size, common_timestamp());
|
||||||
|
try {
|
||||||
|
$imagefile->resizeTo(Avatar::path($filename), $box);
|
||||||
|
} catch (UseFileAsThumbnailException $e) {
|
||||||
|
common_debug('Using uploaded avatar directly without resizing, copying it to: '.$filename);
|
||||||
|
if (!copy($filedata['filepath'], Avatar::path($filename))) {
|
||||||
|
common_debug('Tried to copy image file '.$filedata['filepath'].' to destination '.Avatar::path($filename));
|
||||||
|
throw new ServerException('Could not copy file to destination.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($profile->setOriginal($filename)) {
|
if ($this->scoped->setOriginal($filename)) {
|
||||||
@unlink($filedata['filepath']);
|
@unlink($filedata['filepath']);
|
||||||
unset($_SESSION['FILEDATA']);
|
unset($_SESSION['FILEDATA']);
|
||||||
$this->mode = 'upload';
|
$this->mode = 'upload';
|
||||||
// TRANS: Success message for having updated a user avatar.
|
// TRANS: Success message for having updated a user avatar.
|
||||||
$this->showForm(_('Avatar updated.'), true);
|
return _('Avatar updated.');
|
||||||
} else {
|
|
||||||
// TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason.
|
|
||||||
$this->showForm(_('Failed updating avatar.'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason.
|
||||||
|
throw new ServerException(_('Failed updating avatar.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -396,13 +351,10 @@ class AvatarsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function deleteAvatar()
|
function deleteAvatar()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
Avatar::deleteFromProfile($this->scoped);
|
||||||
$profile = $user->getProfile();
|
|
||||||
|
|
||||||
Avatar::deleteFromProfile($profile);
|
|
||||||
|
|
||||||
// TRANS: Success message for deleting a user avatar.
|
// TRANS: Success message for deleting a user avatar.
|
||||||
$this->showForm(_('Avatar deleted.'), true);
|
return _('Avatar deleted.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,11 +28,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
// This check helps protect against security problems;
|
|
||||||
// your code file can't be executed directly from the web.
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a backup of your own account to the browser
|
* Download a backup of your own account to the browser
|
||||||
@@ -48,38 +44,19 @@ if (!defined('STATUSNET')) {
|
|||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
class BackupaccountAction extends Action
|
class BackupaccountAction extends FormAction
|
||||||
{
|
{
|
||||||
/**
|
protected $form = 'BackupAccount';
|
||||||
* Returns the title of the page
|
|
||||||
*
|
|
||||||
* @return string page title
|
|
||||||
*/
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
// TRANS: Title for backup account page.
|
// TRANS: Title for backup account page.
|
||||||
return _('Backup account');
|
return _('Backup account');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function doPreparation()
|
||||||
* For initializing members of the class.
|
|
||||||
*
|
|
||||||
* @param array $argarray misc. arguments
|
|
||||||
*
|
|
||||||
* @return boolean true
|
|
||||||
*/
|
|
||||||
function prepare($argarray)
|
|
||||||
{
|
{
|
||||||
parent::prepare($argarray);
|
if (!$this->scoped->hasRight(Right::BACKUPACCOUNT)) {
|
||||||
|
|
||||||
$cur = common_current_user();
|
|
||||||
|
|
||||||
if (empty($cur)) {
|
|
||||||
// TRANS: Client exception thrown when trying to backup an account while not logged in.
|
|
||||||
throw new ClientException(_('Only logged-in users can backup their account.'), 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$cur->hasRight(Right::BACKUPACCOUNT)) {
|
|
||||||
// TRANS: Client exception thrown when trying to backup an account without having backup rights.
|
// TRANS: Client exception thrown when trying to backup an account without having backup rights.
|
||||||
throw new ClientException(_('You may not backup your account.'), 403);
|
throw new ClientException(_('You may not backup your account.'), 403);
|
||||||
}
|
}
|
||||||
@@ -87,80 +64,25 @@ class BackupaccountAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function doPost()
|
||||||
* Handler method
|
|
||||||
*
|
|
||||||
* @param array $argarray is ignored since it's now passed in in prepare()
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function handle($argarray=null)
|
|
||||||
{
|
{
|
||||||
parent::handle($argarray);
|
$stream = new UserActivityStream($this->scoped->getUser(), true, UserActivityStream::OUTPUT_RAW);
|
||||||
|
|
||||||
if ($this->isPost()) {
|
header('Content-Disposition: attachment; filename='.urlencode($this->scoped->getNickname()).'.atom');
|
||||||
$this->sendFeed();
|
|
||||||
} else {
|
|
||||||
$this->showPage();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a feed of the user's activities to the browser
|
|
||||||
*
|
|
||||||
* Uses the UserActivityStream class; may take a long time!
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
|
|
||||||
function sendFeed()
|
|
||||||
{
|
|
||||||
$cur = common_current_user();
|
|
||||||
|
|
||||||
$stream = new UserActivityStream($cur, true, UserActivityStream::OUTPUT_RAW);
|
|
||||||
|
|
||||||
header('Content-Disposition: attachment; filename='.$cur->nickname.'.atom');
|
|
||||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||||
|
|
||||||
// @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) {
|
||||||
* Show a little form so that the person can request a backup.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
|
|
||||||
function showContent()
|
|
||||||
{
|
|
||||||
$form = new BackupAccountForm($this);
|
|
||||||
$form->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if read only.
|
|
||||||
*
|
|
||||||
* MAY override
|
|
||||||
*
|
|
||||||
* @param array $args other arguments
|
|
||||||
*
|
|
||||||
* @return boolean is read only action?
|
|
||||||
*/
|
|
||||||
function isReadOnly($args)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return last modified, if applicable.
|
|
||||||
*
|
|
||||||
* MAY override
|
|
||||||
*
|
|
||||||
* @return string last modified http header
|
|
||||||
*/
|
|
||||||
function lastModified()
|
function lastModified()
|
||||||
{
|
{
|
||||||
// For comparison with If-Last-Modified
|
// For comparison with If-Last-Modified
|
||||||
@@ -168,89 +90,8 @@ class BackupaccountAction extends Action
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return etag, if applicable.
|
|
||||||
*
|
|
||||||
* MAY override
|
|
||||||
*
|
|
||||||
* @return string etag http header
|
|
||||||
*/
|
|
||||||
function etag()
|
function etag()
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A form for backing up the account.
|
|
||||||
*
|
|
||||||
* @category Account
|
|
||||||
* @package StatusNet
|
|
||||||
* @author Evan Prodromou <evan@status.net>
|
|
||||||
* @copyright 2010 StatusNet, Inc.
|
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
|
||||||
class BackupAccountForm extends Form
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Class of the form.
|
|
||||||
*
|
|
||||||
* @return string the form's class
|
|
||||||
*/
|
|
||||||
function formClass()
|
|
||||||
{
|
|
||||||
return 'form_profile_backup';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL the form posts to
|
|
||||||
*
|
|
||||||
* @return string the form's action URL
|
|
||||||
*/
|
|
||||||
function action()
|
|
||||||
{
|
|
||||||
return common_local_url('backupaccount');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output form data
|
|
||||||
*
|
|
||||||
* Really, just instructions for doing a backup.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function formData()
|
|
||||||
{
|
|
||||||
$msg =
|
|
||||||
// TRANS: Information displayed on the backup account page.
|
|
||||||
_('You can backup your account data in '.
|
|
||||||
'<a href="http://activitystrea.ms/">Activity Streams</a> '.
|
|
||||||
'format. This is an experimental feature and provides an '.
|
|
||||||
'incomplete backup; private account '.
|
|
||||||
'information like email and IM addresses is not backed up. '.
|
|
||||||
'Additionally, uploaded files and direct messages are not '.
|
|
||||||
'backed up.');
|
|
||||||
$this->out->elementStart('p');
|
|
||||||
$this->out->raw($msg);
|
|
||||||
$this->out->elementEnd('p');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Buttons for the form
|
|
||||||
*
|
|
||||||
* In this case, a single submit button
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function formActions()
|
|
||||||
{
|
|
||||||
$this->out->submit('submit',
|
|
||||||
// TRANS: Submit button to backup an account on the backup account page.
|
|
||||||
_m('BUTTON', 'Backup'),
|
|
||||||
'submit',
|
|
||||||
null,
|
|
||||||
// TRANS: Title for submit button to backup an account on the backup account page.
|
|
||||||
_('Backup your account.'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -43,23 +43,17 @@ class CancelsubscriptionAction extends FormAction
|
|||||||
{
|
{
|
||||||
protected $needPost = true;
|
protected $needPost = true;
|
||||||
|
|
||||||
protected function prepare(array $args=array())
|
protected function doPreparation()
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$profile_id = $this->int('unsubscribeto');
|
$profile_id = $this->int('unsubscribeto');
|
||||||
$this->target = Profile::getKV('id', $profile_id);
|
$this->target = Profile::getKV('id', $profile_id);
|
||||||
if (!$this->target instanceof Profile) {
|
if (!$this->target instanceof Profile) {
|
||||||
throw new NoProfileException($profile_id);
|
throw new NoProfileException($profile_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handlePost()
|
protected function doPost()
|
||||||
{
|
{
|
||||||
parent::handlePost();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$request = Subscription_queue::pkeyGet(array('subscriber' => $this->scoped->id,
|
$request = Subscription_queue::pkeyGet(array('subscriber' => $this->scoped->id,
|
||||||
'subscribed' => $this->target->id));
|
'subscribed' => $this->target->id));
|
||||||
@@ -70,7 +64,7 @@ class CancelsubscriptionAction extends FormAction
|
|||||||
common_debug('Tried to cancel a non-existing pending subscription');
|
common_debug('Tried to cancel a non-existing pending subscription');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StatusNet::isAjax()) {
|
if (GNUsocial::isAjax()) {
|
||||||
$this->startHTML('text/xml;charset=utf-8');
|
$this->startHTML('text/xml;charset=utf-8');
|
||||||
$this->elementStart('head');
|
$this->elementStart('head');
|
||||||
// TRANS: Title after unsubscribing from a group.
|
// TRANS: Title after unsubscribing from a group.
|
||||||
@@ -82,10 +76,7 @@ class CancelsubscriptionAction extends FormAction
|
|||||||
$this->elementEnd('body');
|
$this->elementEnd('body');
|
||||||
$this->endHTML();
|
$this->endHTML();
|
||||||
exit();
|
exit();
|
||||||
} else {
|
|
||||||
common_redirect(common_local_url('subscriptions',
|
|
||||||
array('nickname' => $this->scoped->nickname)),
|
|
||||||
303);
|
|
||||||
}
|
}
|
||||||
|
common_redirect(common_local_url('subscriptions', array('nickname' => $this->scoped->getNickname())), 303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,28 +47,15 @@ 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;
|
||||||
* Initialization.
|
public $page = null;
|
||||||
*
|
public $notices = null;
|
||||||
* @param array $args Web and URL arguments
|
|
||||||
*
|
protected function doPreparation()
|
||||||
* @return boolean false if id not passed in
|
|
||||||
*/
|
|
||||||
protected function prepare(array $args=array())
|
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
$this->conv = Conversation::getByID($this->int('id'));
|
||||||
$convId = $this->int('id');
|
|
||||||
|
|
||||||
$this->conv = Conversation::getKV('id', $convId);
|
|
||||||
if (!$this->conv instanceof Conversation) {
|
|
||||||
throw new ClientException('Could not find specified conversation');
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,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');
|
||||||
@@ -87,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();
|
$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()
|
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->id,
|
'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->id,
|
'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->id,
|
'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 (Activity Streams JSON)')));
|
_('Conversation feed (Atom)')
|
||||||
|
)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,20 +56,20 @@ class DeleteaccountAction extends Action
|
|||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
@@ -204,7 +206,7 @@ class DeleteaccountAction extends Action
|
|||||||
$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,15 +278,12 @@ 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>'.
|
|
||||||
' before deletion.'),
|
|
||||||
common_local_url('backupaccount')) . '</p>';
|
common_local_url('backupaccount')) . '</p>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,8 +300,8 @@ class DeleteAccountForm extends Form
|
|||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -28,80 +28,24 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo FIXME: documentation needed.
|
// @todo FIXME: documentation needed.
|
||||||
class DeletenoticeAction extends Action
|
class DeletenoticeAction extends FormAction
|
||||||
{
|
{
|
||||||
var $error = null;
|
protected $notice = null;
|
||||||
var $user = null;
|
|
||||||
var $notice = null;
|
|
||||||
var $profile = null;
|
|
||||||
var $user_profile = null;
|
|
||||||
|
|
||||||
function prepare($args)
|
protected function doPreparation()
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
$this->notice = Notice::getByID($this->trimmed('notice'));
|
||||||
|
|
||||||
$this->user = common_current_user();
|
if (!$this->scoped->sameAs($this->notice->getProfile()) &&
|
||||||
|
!$this->scoped->hasRight(Right::DELETEOTHERSNOTICE)) {
|
||||||
if (!$this->user) {
|
|
||||||
// TRANS: Error message displayed when trying to perform an action that requires a logged in user.
|
|
||||||
common_user_error(_('Not logged in.'));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$notice_id = $this->trimmed('notice');
|
|
||||||
$this->notice = Notice::getKV($notice_id);
|
|
||||||
|
|
||||||
if (!$this->notice) {
|
|
||||||
// TRANS: Error message displayed trying to delete a non-existing notice.
|
|
||||||
common_user_error(_('No such notice.'));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->profile = $this->notice->getProfile();
|
|
||||||
$this->user_profile = $this->user->getProfile();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle($args)
|
|
||||||
{
|
|
||||||
parent::handle($args);
|
|
||||||
|
|
||||||
if ($this->notice->profile_id != $this->user_profile->id &&
|
|
||||||
!$this->user->hasRight(Right::DELETEOTHERSNOTICE)) {
|
|
||||||
// TRANS: Error message displayed trying to delete a notice that was not made by the current user.
|
// TRANS: Error message displayed trying to delete a notice that was not made by the current user.
|
||||||
common_user_error(_('Cannot delete this notice.'));
|
$this->clientError(_('Cannot delete this notice.'));
|
||||||
exit;
|
|
||||||
}
|
|
||||||
// XXX: Ajax!
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
||||||
$this->deleteNotice();
|
|
||||||
} else if ($_SERVER['REQUEST_METHOD'] == 'GET') {
|
|
||||||
$this->showForm();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$this->formOpts['notice'] = $this->notice;
|
||||||
* Show the page notice
|
|
||||||
*
|
|
||||||
* Shows instructions for the page
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showPageNotice()
|
|
||||||
{
|
|
||||||
$instr = $this->getInstructions();
|
|
||||||
$output = common_markup_to_html($instr);
|
|
||||||
|
|
||||||
$this->elementStart('div', 'instructions');
|
|
||||||
$this->raw($output);
|
|
||||||
$this->elementEnd('div');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInstructions()
|
function getInstructions()
|
||||||
@@ -117,84 +61,15 @@ class DeletenoticeAction extends Action
|
|||||||
return _('Delete notice');
|
return _('Delete notice');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function doPost()
|
||||||
* Wrapper for showing a page
|
|
||||||
*
|
|
||||||
* Stores an error and shows the page
|
|
||||||
*
|
|
||||||
* @param string $error Error, if any
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showForm($error = null)
|
|
||||||
{
|
{
|
||||||
$this->error = $error;
|
|
||||||
$this->showPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert delete notice form into the content
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showContent()
|
|
||||||
{
|
|
||||||
$this->elementStart('form', array('id' => 'form_notice_delete',
|
|
||||||
'class' => 'form_settings',
|
|
||||||
'method' => 'post',
|
|
||||||
'action' => common_local_url('deletenotice')));
|
|
||||||
$this->elementStart('fieldset');
|
|
||||||
// TRANS: Fieldset legend for the delete notice form.
|
|
||||||
$this->element('legend', null, _('Delete notice'));
|
|
||||||
$this->hidden('token', common_session_token());
|
|
||||||
$this->hidden('notice', $this->trimmed('notice'));
|
|
||||||
// TRANS: Message for the delete notice form.
|
|
||||||
$this->element('p', null, _('Are you sure you want to delete this notice?'));
|
|
||||||
$this->submit('form_action-no',
|
|
||||||
// TRANS: Button label on the delete notice form.
|
|
||||||
_m('BUTTON','No'),
|
|
||||||
'submit form_action-primary',
|
|
||||||
'no',
|
|
||||||
// TRANS: Submit button title for 'No' when deleting a notice.
|
|
||||||
_('Do not delete this notice.'));
|
|
||||||
$this->submit('form_action-yes',
|
|
||||||
// TRANS: Button label on the delete notice form.
|
|
||||||
_m('BUTTON','Yes'),
|
|
||||||
'submit form_action-secondary',
|
|
||||||
'yes',
|
|
||||||
// TRANS: Submit button title for 'Yes' when deleting a notice.
|
|
||||||
_('Delete this notice.'));
|
|
||||||
$this->elementEnd('fieldset');
|
|
||||||
$this->elementEnd('form');
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteNotice()
|
|
||||||
{
|
|
||||||
// CSRF protection
|
|
||||||
$token = $this->trimmed('token');
|
|
||||||
|
|
||||||
if (!$token || $token != common_session_token()) {
|
|
||||||
// TRANS: Client error displayed when the session token does not match or is not given.
|
|
||||||
$this->showForm(_('There was a problem with your session token. ' .
|
|
||||||
'Try again, please.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->arg('yes')) {
|
if ($this->arg('yes')) {
|
||||||
if (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) {
|
if (Event::handle('StartDeleteOwnNotice', array($this->scoped->getUser(), $this->notice))) {
|
||||||
$this->notice->delete();
|
$this->notice->deleteAs($this->scoped);
|
||||||
Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
|
Event::handle('EndDeleteOwnNotice', array($this->scoped->getUser(), $this->notice));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = common_get_returnto();
|
common_redirect(common_get_returnto(), 303);
|
||||||
|
|
||||||
if ($url) {
|
|
||||||
common_set_returnto(null);
|
|
||||||
} else {
|
|
||||||
$url = common_local_url('public');
|
|
||||||
}
|
|
||||||
|
|
||||||
common_redirect($url, 303);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a user
|
* Delete a user
|
||||||
@@ -44,33 +42,30 @@ class DeleteuserAction extends ProfileFormAction
|
|||||||
{
|
{
|
||||||
var $user = null;
|
var $user = null;
|
||||||
|
|
||||||
/**
|
function prepare(array $args=array())
|
||||||
* Take arguments for running
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST args
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
function prepare($args)
|
|
||||||
{
|
{
|
||||||
if (!parent::prepare($args)) {
|
if (!parent::prepare($args)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cur = common_current_user();
|
assert($this->scoped instanceof Profile);
|
||||||
|
|
||||||
assert(!empty($cur)); // checked by parent
|
if (!$this->scoped->hasRight(Right::DELETEUSER)) {
|
||||||
|
|
||||||
if (!$cur->hasRight(Right::DELETEUSER)) {
|
|
||||||
// TRANS: Client error displayed when trying to delete a user without having the right to delete users.
|
// TRANS: Client error displayed when trying to delete a user without having the right to delete users.
|
||||||
$this->clientError(_('You cannot delete users.'));
|
throw new AuthorizationException(_('You cannot delete users.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->user = User::getKV('id', $this->profile->id);
|
try {
|
||||||
|
$this->user = $this->profile->getUser();
|
||||||
if (empty($this->user)) {
|
} catch (NoSuchUserException $e) {
|
||||||
// TRANS: Client error displayed when trying to delete a non-local user.
|
// TRANS: Client error displayed when trying to delete a non-local user.
|
||||||
$this->clientError(_('You can only delete local users.'));
|
throw new ClientException(_('You can only delete local users.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only administrators can delete other privileged users (such as others who have the right to silence).
|
||||||
|
if ($this->profile->isPrivileged() && !$this->scoped->hasRole(Profile_role::ADMINISTRATOR)) {
|
||||||
|
// TRANS: Client error displayed when trying to delete a user that has been granted moderation privileges
|
||||||
|
throw new AuthorizationException(_('You cannot delete other privileged users.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -85,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')) {
|
||||||
|
|||||||
@@ -28,9 +28,7 @@
|
|||||||
* 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('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Documentation class.
|
* Documentation class.
|
||||||
@@ -42,16 +40,14 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
class DocAction extends Action
|
class DocAction extends ManagedAction
|
||||||
{
|
{
|
||||||
var $output = null;
|
var $output = null;
|
||||||
var $filename = null;
|
var $filename = null;
|
||||||
var $title = null;
|
var $title = null;
|
||||||
|
|
||||||
function prepare($args)
|
protected function doPreparation()
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$this->title = $this->trimmed('title');
|
$this->title = $this->trimmed('title');
|
||||||
if (!preg_match('/^[a-zA-Z0-9_-]*$/', $this->title)) {
|
if (!preg_match('/^[a-zA-Z0-9_-]*$/', $this->title)) {
|
||||||
$this->title = 'help';
|
$this->title = 'help';
|
||||||
@@ -59,52 +55,11 @@ class DocAction extends Action
|
|||||||
$this->output = null;
|
$this->output = null;
|
||||||
|
|
||||||
$this->loadDoc();
|
$this->loadDoc();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function title()
|
||||||
* Handle a request
|
|
||||||
*
|
|
||||||
* @param array $args array of arguments
|
|
||||||
*
|
|
||||||
* @return nothing
|
|
||||||
*/
|
|
||||||
function handle($args)
|
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
return ucfirst($this->title);
|
||||||
$this->showPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Page title
|
|
||||||
*
|
|
||||||
* Gives the page title of the document. Override default for hAtom entry.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showPageTitle()
|
|
||||||
{
|
|
||||||
$this->element('h1', array('class' => 'entry-title'), $this->title());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block for content.
|
|
||||||
*
|
|
||||||
* Overrides default from Action to wrap everything in an hAtom entry.
|
|
||||||
*
|
|
||||||
* @return void.
|
|
||||||
*/
|
|
||||||
function showContentBlock()
|
|
||||||
{
|
|
||||||
$this->elementStart('div', array('id' => 'content', 'class' => 'h-entry'));
|
|
||||||
$this->showPageTitle();
|
|
||||||
$this->showPageNoticeBlock();
|
|
||||||
$this->elementStart('div', array('id' => 'content_inner',
|
|
||||||
'class' => 'e-content'));
|
|
||||||
// show the actual content (forms, lists, whatever)
|
|
||||||
$this->showContent();
|
|
||||||
$this->elementEnd('div');
|
|
||||||
$this->elementEnd('div');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,16 +74,9 @@ class DocAction extends Action
|
|||||||
$this->raw($this->output);
|
$this->raw($this->output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function showNoticeForm()
|
||||||
* Page title.
|
|
||||||
*
|
|
||||||
* Uses the title of the document.
|
|
||||||
*
|
|
||||||
* @return page title
|
|
||||||
*/
|
|
||||||
function title()
|
|
||||||
{
|
{
|
||||||
return ucfirst($this->title);
|
// no notice form
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,11 +122,15 @@ class DocNav extends Menu
|
|||||||
{
|
{
|
||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
|
if (Event::handle('StartDocNav', array($this))) {
|
||||||
$stub = new HomeStubNav($this->action);
|
$stub = new HomeStubNav($this->action);
|
||||||
$this->submenu(_m('MENU','Home'), $stub);
|
$this->submenu(_m('MENU','Home'), $stub);
|
||||||
|
|
||||||
$docs = new DocListNav($this->action);
|
$docs = new DocListNav($this->action);
|
||||||
$this->submenu(_m('MENU','Docs'), $docs);
|
$this->submenu(_m('MENU','Docs'), $docs);
|
||||||
|
|
||||||
|
Event::handle('EndDocNav', array($this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,75 +148,32 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,40 +196,49 @@ 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.
|
// TRANS: Group edit form validation error.
|
||||||
_m('Description is too long (maximum %d character).',
|
_m(
|
||||||
|
'Description is too long (maximum %d character).',
|
||||||
'Description is too long (maximum %d characters).',
|
'Description is too long (maximum %d characters).',
|
||||||
User_group::maxDescription()),
|
User_group::maxDescription()
|
||||||
User_group::maxDescription()));
|
),
|
||||||
|
User_group::maxDescription()
|
||||||
|
), true);
|
||||||
return;
|
return;
|
||||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
} elseif (!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).'));
|
$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(
|
||||||
|
_m(
|
||||||
'Too many aliases! Maximum %d allowed.',
|
'Too many aliases! Maximum %d allowed.',
|
||||||
common_config('group', 'maxaliases')),
|
'Too many aliases! Maximum %d allowed.',
|
||||||
common_config('group', 'maxaliases')));
|
common_config('group', 'maxaliases')
|
||||||
|
),
|
||||||
|
common_config('group', 'maxaliases')
|
||||||
|
), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,10 +247,10 @@ 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;
|
||||||
@@ -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) {
|
if ($this->group->nickname != $orig->nickname) {
|
||||||
common_redirect(common_local_url('editgroup', array('nickname' => $this->group->nickname)), 303);
|
common_redirect(common_local_url('editgroup', ['nickname' => $this->group->nickname]), 303);
|
||||||
} else {
|
|
||||||
// TRANS: Group edit form success message.
|
|
||||||
$this->showForm(_('Options saved.'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TRANS: Group edit form success message.
|
||||||
|
$this->setMessage(_('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 {
|
||||||
|
|||||||
@@ -28,11 +28,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings for email
|
* Settings for email
|
||||||
@@ -91,7 +87,7 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = $this->scoped->getUser();
|
||||||
|
|
||||||
$this->elementStart('form', array('method' => 'post',
|
$this->elementStart('form', array('method' => 'post',
|
||||||
'id' => 'form_settings_email',
|
'id' => 'form_settings_email',
|
||||||
@@ -112,8 +108,8 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
// TRANS: Button label to remove a confirmed e-mail address.
|
// TRANS: Button label to remove a confirmed e-mail address.
|
||||||
$this->submit('remove', _m('BUTTON','Remove'));
|
$this->submit('remove', _m('BUTTON','Remove'));
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$confirm = $this->getConfirmation();
|
$confirm = $this->getConfirmation();
|
||||||
if ($confirm) {
|
|
||||||
$this->element('p', array('id' => 'form_unconfirmed'), $confirm->address);
|
$this->element('p', array('id' => 'form_unconfirmed'), $confirm->address);
|
||||||
$this->element('p', array('class' => 'form_note'),
|
$this->element('p', array('class' => 'form_note'),
|
||||||
// TRANS: Form note in e-mail settings form.
|
// TRANS: Form note in e-mail settings form.
|
||||||
@@ -123,12 +119,12 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
$this->hidden('email', $confirm->address);
|
$this->hidden('email', $confirm->address);
|
||||||
// TRANS: Button label to cancel an e-mail address confirmation procedure.
|
// TRANS: Button label to cancel an e-mail address confirmation procedure.
|
||||||
$this->submit('cancel', _m('BUTTON','Cancel'));
|
$this->submit('cancel', _m('BUTTON','Cancel'));
|
||||||
} else {
|
} catch (NoResultException $e) {
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
// TRANS: Field label for e-mail address input in e-mail settings form.
|
// TRANS: Field label for e-mail address input in e-mail settings form.
|
||||||
$this->input('email', _('Email address'),
|
$this->input('email', _('Email address'),
|
||||||
($this->arg('email')) ? $this->arg('email') : null,
|
$this->trimmed('email') ?: null,
|
||||||
// TRANS: Instructions for e-mail address input form. Do not translate
|
// TRANS: Instructions for e-mail address input form. Do not translate
|
||||||
// TRANS: "example.org". It is one of the domain names reserved for
|
// TRANS: "example.org". It is one of the domain names reserved for
|
||||||
// TRANS: use in examples by http://www.rfc-editor.org/rfc/rfc2606.txt.
|
// TRANS: use in examples by http://www.rfc-editor.org/rfc/rfc2606.txt.
|
||||||
@@ -231,12 +227,6 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
_('Allow friends to nudge me and send me an email.'),
|
_('Allow friends to nudge me and send me an email.'),
|
||||||
$user->emailnotifynudge);
|
$user->emailnotifynudge);
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementStart('li');
|
|
||||||
$this->checkbox('emailmicroid',
|
|
||||||
// TRANS: Checkbox label in e-mail preferences form.
|
|
||||||
_('Publish a MicroID for my email address.'),
|
|
||||||
$user->emailmicroid);
|
|
||||||
$this->elementEnd('li');
|
|
||||||
Event::handle('EndEmailFormData', array($this, $this->scoped));
|
Event::handle('EndEmailFormData', array($this, $this->scoped));
|
||||||
}
|
}
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
@@ -254,56 +244,36 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function getConfirmation()
|
function getConfirmation()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$confirm = new Confirm_address();
|
$confirm = new Confirm_address();
|
||||||
|
|
||||||
$confirm->user_id = $user->id;
|
$confirm->user_id = $this->scoped->getID();
|
||||||
$confirm->address_type = 'email';
|
$confirm->address_type = 'email';
|
||||||
|
|
||||||
if ($confirm->find(true)) {
|
if ($confirm->find(true)) {
|
||||||
return $confirm;
|
return $confirm;
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
throw new NoResultException($confirm);
|
||||||
* Handle posts
|
}
|
||||||
*
|
|
||||||
* Since there are a lot of different options on the page, we
|
protected function doPost()
|
||||||
* figure out what we're supposed to do based on which button was
|
|
||||||
* pushed
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function handlePost()
|
|
||||||
{
|
{
|
||||||
// CSRF protection
|
if ($this->arg('save')) {
|
||||||
$token = $this->trimmed('token');
|
return $this->savePreferences();
|
||||||
if (!$token || $token != common_session_token()) {
|
} else if ($this->arg('add')) {
|
||||||
// TRANS: Client error displayed when the session token does not match or is not given.
|
return $this->addAddress();
|
||||||
$this->show_form(_('There was a problem with your session token. '.
|
} else if ($this->arg('cancel')) {
|
||||||
'Try again, please.'));
|
return $this->cancelConfirmation();
|
||||||
return;
|
} else if ($this->arg('remove')) {
|
||||||
|
return $this->removeAddress();
|
||||||
|
} else if ($this->arg('removeincoming')) {
|
||||||
|
return $this->removeIncoming();
|
||||||
|
} else if ($this->arg('newincoming')) {
|
||||||
|
return $this->newIncoming();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->arg('save')) {
|
|
||||||
$this->savePreferences();
|
|
||||||
} else if ($this->arg('add')) {
|
|
||||||
$this->addAddress();
|
|
||||||
} else if ($this->arg('cancel')) {
|
|
||||||
$this->cancelConfirmation();
|
|
||||||
} else if ($this->arg('remove')) {
|
|
||||||
$this->removeAddress();
|
|
||||||
} else if ($this->arg('removeincoming')) {
|
|
||||||
$this->removeIncoming();
|
|
||||||
} else if ($this->arg('newincoming')) {
|
|
||||||
$this->newIncoming();
|
|
||||||
} else {
|
|
||||||
// TRANS: Message given submitting a form with an unknown action in e-mail settings.
|
// TRANS: Message given submitting a form with an unknown action in e-mail settings.
|
||||||
$this->showForm(_('Unexpected form submission.'));
|
throw new ClientException(_('Unexpected form submission.'));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -313,44 +283,38 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function savePreferences()
|
function savePreferences()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) {
|
if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) {
|
||||||
$emailnotifysub = $this->boolean('emailnotifysub');
|
$emailnotifysub = $this->booleanintstring('emailnotifysub');
|
||||||
$emailnotifymsg = $this->boolean('emailnotifymsg');
|
$emailnotifymsg = $this->booleanintstring('emailnotifymsg');
|
||||||
$emailnotifynudge = $this->boolean('emailnotifynudge');
|
$emailnotifynudge = $this->booleanintstring('emailnotifynudge');
|
||||||
$emailnotifyattn = $this->boolean('emailnotifyattn');
|
$emailnotifyattn = $this->booleanintstring('emailnotifyattn');
|
||||||
$emailmicroid = $this->boolean('emailmicroid');
|
$emailpost = $this->booleanintstring('emailpost');
|
||||||
$emailpost = $this->boolean('emailpost');
|
|
||||||
|
|
||||||
assert(!is_null($user)); // should already be checked
|
|
||||||
|
|
||||||
|
$user = $this->scoped->getUser();
|
||||||
$user->query('BEGIN');
|
$user->query('BEGIN');
|
||||||
|
|
||||||
$original = clone($user);
|
$original = clone($user);
|
||||||
|
|
||||||
$user->emailnotifysub = $emailnotifysub;
|
$user->emailnotifysub = $emailnotifysub;
|
||||||
$user->emailnotifymsg = $emailnotifymsg;
|
$user->emailnotifymsg = $emailnotifymsg;
|
||||||
$user->emailnotifynudge = $emailnotifynudge;
|
$user->emailnotifynudge = $emailnotifynudge;
|
||||||
$user->emailnotifyattn = $emailnotifyattn;
|
$user->emailnotifyattn = $emailnotifyattn;
|
||||||
$user->emailmicroid = $emailmicroid;
|
|
||||||
$user->emailpost = $emailpost;
|
$user->emailpost = $emailpost;
|
||||||
|
|
||||||
$result = $user->update($original);
|
$result = $user->update($original);
|
||||||
|
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||||
|
$user->query('ROLLBACK');
|
||||||
// TRANS: Server error thrown on database error updating e-mail preferences.
|
// TRANS: Server error thrown on database error updating e-mail preferences.
|
||||||
$this->serverError(_('Could not update user.'));
|
throw new ServerException(_('Could not update user.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->query('COMMIT');
|
$user->query('COMMIT');
|
||||||
|
|
||||||
Event::handle('EndEmailSaveForm', array($this, $this->scoped));
|
Event::handle('EndEmailSaveForm', array($this, $this->scoped));
|
||||||
|
|
||||||
// TRANS: Confirmation message for successful e-mail preferences save.
|
|
||||||
$this->showForm(_('Email preferences saved.'), true);
|
|
||||||
}
|
}
|
||||||
|
// TRANS: Confirmation message for successful e-mail preferences save.
|
||||||
|
return _('Email preferences saved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -360,38 +324,32 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function addAddress()
|
function addAddress()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = $this->scoped->getUser();
|
||||||
|
|
||||||
$email = $this->trimmed('email');
|
$email = $this->trimmed('email');
|
||||||
|
|
||||||
// Some validation
|
// Some validation
|
||||||
|
|
||||||
if (!$email) {
|
if (empty($email)) {
|
||||||
// TRANS: Message given saving e-mail address without having provided one.
|
// TRANS: Message given saving e-mail address without having provided one.
|
||||||
$this->showForm(_('No email address.'));
|
throw new ClientException(_('No email address.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$email = common_canonical_email($email);
|
$email = common_canonical_email($email);
|
||||||
|
|
||||||
if (!$email) {
|
if (empty($email)) {
|
||||||
// TRANS: Message given saving e-mail address that cannot be normalised.
|
// TRANS: Message given saving e-mail address that cannot be normalised.
|
||||||
$this->showForm(_('Cannot normalize that email address.'));
|
throw new ClientException(_('Cannot normalize that email address.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!Validate::email($email, common_config('email', 'check_domain'))) {
|
if (!Validate::email($email, common_config('email', 'check_domain'))) {
|
||||||
// TRANS: Message given saving e-mail address that not valid.
|
// TRANS: Message given saving e-mail address that not valid.
|
||||||
$this->showForm(_('Not a valid email address.'));
|
throw new ClientException(_('Not a valid email address.'));
|
||||||
return;
|
|
||||||
} else if ($user->email == $email) {
|
} else if ($user->email == $email) {
|
||||||
// TRANS: Message given saving e-mail address that is already set.
|
// TRANS: Message given saving e-mail address that is already set.
|
||||||
$this->showForm(_('That is already your email address.'));
|
throw new ClientException(_('That is already your email address.'));
|
||||||
return;
|
|
||||||
} else if ($this->emailExists($email)) {
|
} else if ($this->emailExists($email)) {
|
||||||
// TRANS: Message given saving e-mail address that is already set for another user.
|
// TRANS: Message given saving e-mail address that is already set for another user.
|
||||||
$this->showForm(_('That email address already belongs '.
|
throw new ClientException(_('That email address already belongs to another user.'));
|
||||||
'to another user.'));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartAddEmailAddress', array($user, $email))) {
|
if (Event::handle('StartAddEmailAddress', array($user, $email))) {
|
||||||
@@ -400,7 +358,7 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
|
|
||||||
$confirm->address = $email;
|
$confirm->address = $email;
|
||||||
$confirm->address_type = 'email';
|
$confirm->address_type = 'email';
|
||||||
$confirm->user_id = $user->id;
|
$confirm->user_id = $user->getID();
|
||||||
$confirm->code = common_confirmation_code(64);
|
$confirm->code = common_confirmation_code(64);
|
||||||
|
|
||||||
$result = $confirm->insert();
|
$result = $confirm->insert();
|
||||||
@@ -408,20 +366,18 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
common_log_db_error($confirm, 'INSERT', __FILE__);
|
common_log_db_error($confirm, 'INSERT', __FILE__);
|
||||||
// TRANS: Server error thrown on database error adding e-mail confirmation code.
|
// TRANS: Server error thrown on database error adding e-mail confirmation code.
|
||||||
$this->serverError(_('Could not insert confirmation code.'));
|
throw new ServerException(_('Could not insert confirmation code.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
mail_confirm_address($user, $confirm->code, $user->nickname, $email);
|
$confirm->sendConfirmation();
|
||||||
|
|
||||||
Event::handle('EndAddEmailAddress', array($user, $email));
|
Event::handle('EndAddEmailAddress', array($user, $email));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TRANS: Message given saving valid e-mail address that is to be confirmed.
|
// TRANS: Message given saving valid e-mail address that is to be confirmed.
|
||||||
$msg = _('A confirmation code was sent to the email address you added. '.
|
return _('A confirmation code was sent to the email address you added. '.
|
||||||
'Check your inbox (and spam box!) for the code and instructions '.
|
'Check your inbox (and spam box!) for the code and instructions '.
|
||||||
'on how to use it.');
|
'on how to use it.');
|
||||||
|
|
||||||
$this->showForm($msg, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -431,31 +387,23 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function cancelConfirmation()
|
function cancelConfirmation()
|
||||||
{
|
{
|
||||||
$email = $this->arg('email');
|
$email = $this->trimmed('email');
|
||||||
|
|
||||||
|
try {
|
||||||
$confirm = $this->getConfirmation();
|
$confirm = $this->getConfirmation();
|
||||||
|
if ($confirm->address !== $email) {
|
||||||
if (!$confirm) {
|
|
||||||
// TRANS: Message given canceling e-mail address confirmation that is not pending.
|
|
||||||
$this->showForm(_('No pending confirmation to cancel.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($confirm->address != $email) {
|
|
||||||
// TRANS: Message given canceling e-mail address confirmation for the wrong e-mail address.
|
// TRANS: Message given canceling e-mail address confirmation for the wrong e-mail address.
|
||||||
$this->showForm(_('That is the wrong email address.'));
|
throw new ClientException(_('That is the wrong email address.'));
|
||||||
return;
|
}
|
||||||
|
} catch (NoResultException $e) {
|
||||||
|
// TRANS: Message given canceling e-mail address confirmation that is not pending.
|
||||||
|
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $confirm->delete();
|
$confirm->delete();
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
common_log_db_error($confirm, 'DELETE', __FILE__);
|
|
||||||
// TRANS: Server error thrown on database error canceling e-mail address confirmation.
|
|
||||||
$this->serverError(_('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.
|
||||||
$this->showForm(_('Email confirmation cancelled.'), true);
|
return _('Email confirmation cancelled.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -467,26 +415,22 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
$email = $this->arg('email');
|
$email = $this->trimmed('email');
|
||||||
|
|
||||||
// Maybe an old tab open...?
|
// Maybe an old tab open...?
|
||||||
|
if ($user->email !== $email) {
|
||||||
if ($user->email != $email) {
|
|
||||||
// TRANS: Message given trying to remove an e-mail address that is not
|
// TRANS: Message given trying to remove an e-mail address that is not
|
||||||
// TRANS: registered for the active user.
|
// TRANS: registered for the active user.
|
||||||
$this->showForm(_('That is not your email address.'));
|
throw new ClientException(_('That is not your email address.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$original = clone($user);
|
$original = clone($user);
|
||||||
|
|
||||||
$user->email = null;
|
$user->email = null;
|
||||||
|
|
||||||
// Throws exception on failure. Also performs it within a transaction.
|
// Throws exception on failure. Also performs it within a transaction.
|
||||||
$user->updateWithKeys($original);
|
$user->updateWithKeys($original);
|
||||||
|
|
||||||
// TRANS: Message given after successfully removing a registered e-mail address.
|
// TRANS: Message given after successfully removing a registered e-mail address.
|
||||||
$this->showForm(_('The email address was removed.'), true);
|
return _('The email address was removed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -498,22 +442,19 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
if (!$user->incomingemail) {
|
if (empty($user->incomingemail)) {
|
||||||
// TRANS: Form validation error displayed when trying to remove an incoming e-mail address while no address has been set.
|
// TRANS: Form validation error displayed when trying to remove an incoming e-mail address while no address has been set.
|
||||||
$this->showForm(_('No incoming email address.'));
|
throw new AlreadyFulfilledException(_('No incoming email address.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$orig = clone($user);
|
$orig = clone($user);
|
||||||
|
|
||||||
$user->incomingemail = null;
|
$user->incomingemail = null;
|
||||||
$user->emailpost = 0;
|
$user->emailpost = 0;
|
||||||
|
|
||||||
// Throws exception on failure. Also performs it within a transaction.
|
// Throws exception on failure. Also performs it within a transaction.
|
||||||
$user->updateWithKeys($orig);
|
$user->updateWithKeys($orig);
|
||||||
|
|
||||||
// TRANS: Message given after successfully removing an incoming e-mail address.
|
// TRANS: Message given after successfully removing an incoming e-mail address.
|
||||||
$this->showForm(_('Incoming email address removed.'), true);
|
return _('Incoming email address removed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -524,17 +465,14 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
function newIncoming()
|
function newIncoming()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
$orig = clone($user);
|
$orig = clone($user);
|
||||||
|
|
||||||
$user->incomingemail = mail_new_incoming_address();
|
$user->incomingemail = mail_new_incoming_address();
|
||||||
$user->emailpost = 1;
|
$user->emailpost = 1;
|
||||||
|
|
||||||
// Throws exception on failure. Also performs it within a transaction.
|
// Throws exception on failure. Also performs it within a transaction.
|
||||||
$user->updateWithKeys($orig);
|
$user->updateWithKeys($orig);
|
||||||
|
|
||||||
// TRANS: Message given after successfully adding an incoming e-mail address.
|
// TRANS: Message given after successfully adding an incoming e-mail address.
|
||||||
$this->showForm(_('New incoming email address added.'), true);
|
return _('New incoming email address added.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -553,10 +491,10 @@ class EmailsettingsAction extends SettingsAction
|
|||||||
|
|
||||||
$other = User::getKV('email', $email);
|
$other = User::getKV('email', $email);
|
||||||
|
|
||||||
if (!$other) {
|
if (!$other instanceof User) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return $other->id != $user->id;
|
return $other->id != $user->id;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,24 +17,22 @@
|
|||||||
* 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('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
|
|
||||||
define('LISTENER', 1);
|
define('LISTENER', 1);
|
||||||
define('LISTENEE', -1);
|
define('LISTENEE', -1);
|
||||||
define('BOTH', 0);
|
define('BOTH', 0);
|
||||||
|
|
||||||
// @todo XXX: Documentation missing.
|
// @todo XXX: Documentation missing.
|
||||||
class FoafAction extends Action
|
class FoafAction extends ManagedAction
|
||||||
{
|
{
|
||||||
function isReadOnly($args)
|
function isReadOnly($args)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
protected function doPreparation()
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$nickname_arg = $this->arg('nickname');
|
$nickname_arg = $this->arg('nickname');
|
||||||
|
|
||||||
if (empty($nickname_arg)) {
|
if (empty($nickname_arg)) {
|
||||||
@@ -69,10 +67,8 @@ class FoafAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
public function showPage()
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
|
||||||
|
|
||||||
header('Content-Type: application/rdf+xml');
|
header('Content-Type: application/rdf+xml');
|
||||||
|
|
||||||
$this->startXML();
|
$this->startXML();
|
||||||
@@ -94,7 +90,7 @@ class FoafAction extends Action
|
|||||||
|
|
||||||
// Would be nice to tell if they were a Person or not (e.g. a #person usertag?)
|
// Would be nice to tell if they were a Person or not (e.g. a #person usertag?)
|
||||||
$this->elementStart('Agent', array('rdf:about' => $this->user->getUri()));
|
$this->elementStart('Agent', array('rdf:about' => $this->user->getUri()));
|
||||||
if ($this->user->email) {
|
if (common_config('foaf', 'mbox_sha1sum') && $this->user->email) {
|
||||||
$this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email));
|
$this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email));
|
||||||
}
|
}
|
||||||
if ($this->profile->fullname) {
|
if ($this->profile->fullname) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -28,12 +28,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/noticelist.php';
|
|
||||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permalink for a group
|
* Permalink for a group
|
||||||
@@ -47,54 +42,23 @@ require_once INSTALLDIR.'/lib/feedlist.php';
|
|||||||
* @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 Action
|
class GroupbyidAction extends ShowgroupAction
|
||||||
{
|
{
|
||||||
/** group we're viewing. */
|
/** group we're viewing. */
|
||||||
var $group = null;
|
protected $group = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this page read-only?
|
|
||||||
*
|
|
||||||
* @return boolean true
|
|
||||||
*/
|
|
||||||
function isReadOnly($args)
|
function isReadOnly($args)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
protected function doPreparation()
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
$this->group = User_group::getByID($this->arg('id'));
|
||||||
|
$this->target = $this->group->getProfile();
|
||||||
|
|
||||||
$id = $this->arg('id');
|
if ($this->target->isLocal()) {
|
||||||
|
common_redirect($this->target->getUrl());
|
||||||
if (!$id) {
|
|
||||||
// TRANS: Client error displayed referring to a group's permalink without providing a group ID.
|
|
||||||
$this->clientError(_('No ID.'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
common_debug("Got ID $id");
|
|
||||||
|
|
||||||
$this->group = User_group::getKV('id', $id);
|
|
||||||
|
|
||||||
if (!$this->group) {
|
|
||||||
// TRANS: Client error displayed referring to a group's permalink for a non-existing group ID.
|
|
||||||
$this->clientError(_('No such group.'), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the request
|
|
||||||
*
|
|
||||||
* Shows a profile for the group, some controls, and a list of
|
|
||||||
* group notices.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function handle($args)
|
|
||||||
{
|
|
||||||
common_redirect($this->group->homeUrl(), 303);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,14 +28,10 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
define('MAX_ORIGINAL', 480);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload an avatar
|
* Upload an avatar
|
||||||
*
|
*
|
||||||
@@ -46,21 +42,257 @@ define('MAX_ORIGINAL', 480);
|
|||||||
* @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);
|
||||||
|
|
||||||
@@ -110,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,20 +377,22 @@ 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(
|
||||||
|
$this->group->id,
|
||||||
image_type_to_extension($type),
|
image_type_to_extension($type),
|
||||||
null,
|
null,
|
||||||
'group-temp-'.common_timestamp());
|
'group-temp-' . common_timestamp()
|
||||||
|
);
|
||||||
|
|
||||||
$filepath = Avatar::path($filename);
|
$filepath = Avatar::path($filename);
|
||||||
|
|
||||||
@@ -367,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'];
|
||||||
|
|
||||||
@@ -386,68 +438,59 @@ 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);
|
$size = min($dest_w, $dest_h, common_config('avatar', 'maxsize'));
|
||||||
$size = ($size > MAX_ORIGINAL) ? MAX_ORIGINAL:$size;
|
$box = array('width' => $size, 'height' => $size,
|
||||||
|
'x' => $dest_x, 'y' => $dest_y,
|
||||||
|
'w' => $dest_w, 'h' => $dest_h);
|
||||||
|
|
||||||
$imagefile = new ImageFile($this->group->id, $filedata['filepath']);
|
$profile = $this->group->getProfile();
|
||||||
$filename = $imagefile->resize($size, $dest_x, $dest_y, $dest_w, $dest_h);
|
|
||||||
|
|
||||||
if ($this->group->setOriginal($filename)) {
|
$imagefile = new ImageFile(null, $filedata['filepath']);
|
||||||
|
$filename = Avatar::filename(
|
||||||
|
$profile->getID(),
|
||||||
|
image_type_to_extension($imagefile->preferredType()),
|
||||||
|
$size,
|
||||||
|
common_timestamp()
|
||||||
|
);
|
||||||
|
|
||||||
|
$imagefile->resizeTo(Avatar::path($filename), $box);
|
||||||
|
|
||||||
|
if ($profile->setOriginal($filename)) {
|
||||||
@unlink($filedata['filepath']);
|
@unlink($filedata['filepath']);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,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/rssaction.php';
|
|
||||||
|
|
||||||
define('MEMBERS_PER_SECTION', 27);
|
define('MEMBERS_PER_SECTION', 27);
|
||||||
|
|
||||||
@@ -45,10 +41,10 @@ define('MEMBERS_PER_SECTION', 27);
|
|||||||
* @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 groupRssAction extends Rss10Action
|
class GroupRssAction extends TargetedRss10Action
|
||||||
{
|
{
|
||||||
/** group we're viewing. */
|
/** group we're viewing. */
|
||||||
var $group = null;
|
protected $group = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this page read-only?
|
* Is this page read-only?
|
||||||
@@ -60,18 +56,8 @@ class groupRssAction extends Rss10Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function doStreamPreparation()
|
||||||
* Prepare the action
|
|
||||||
*
|
|
||||||
* Reads and validates arguments and instantiates the attributes.
|
|
||||||
*
|
|
||||||
* @param array $args $_REQUEST args
|
|
||||||
*
|
|
||||||
* @return boolean success flag
|
|
||||||
*/
|
|
||||||
function prepare($args)
|
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$nickname_arg = $this->arg('nickname');
|
$nickname_arg = $this->arg('nickname');
|
||||||
$nickname = common_canonical_nickname($nickname_arg);
|
$nickname = common_canonical_nickname($nickname_arg);
|
||||||
@@ -90,52 +76,32 @@ class groupRssAction extends Rss10Action
|
|||||||
|
|
||||||
$local = Local_group::getKV('nickname', $nickname);
|
$local = Local_group::getKV('nickname', $nickname);
|
||||||
|
|
||||||
if (!$local) {
|
if (!$local instanceof Local_group) {
|
||||||
// TRANS: Client error displayed when requesting a group RSS feed for group that does not exist.
|
// TRANS: Client error displayed when requesting a group RSS feed for group that does not exist.
|
||||||
$this->clientError(_('No such group.'), 404);
|
$this->clientError(_('No such group.'), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->group = User_group::getKV('id', $local->group_id);
|
$this->group = $local->getGroup();
|
||||||
|
$this->target = $this->group->getProfile();
|
||||||
if (!$this->group) {
|
|
||||||
// TRANS: Client error displayed when requesting a group RSS feed for an object that is not a group.
|
|
||||||
$this->clientError(_('No such group.'), 404);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->notices = $this->getNotices($this->limit);
|
protected function getNotices()
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNotices($limit=0)
|
|
||||||
{
|
{
|
||||||
$group = $this->group;
|
$stream = $this->group->getNotices(0, $this->limit);
|
||||||
|
return $stream->fetchAll();
|
||||||
if (is_null($group)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$notices = array();
|
|
||||||
$notice = $group->getNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit);
|
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
|
||||||
$notices[] = clone($notice);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $notices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChannel()
|
function getChannel()
|
||||||
{
|
{
|
||||||
$group = $this->group;
|
|
||||||
$c = array('url' => common_local_url('grouprss',
|
$c = array('url' => common_local_url('grouprss',
|
||||||
array('nickname' =>
|
array('nickname' =>
|
||||||
$group->nickname)),
|
$this->target->getNickname())),
|
||||||
// TRANS: Message is used as link title. %s is a user nickname.
|
// TRANS: Message is used as link title. %s is a user nickname.
|
||||||
'title' => sprintf(_('%s timeline'), $group->nickname),
|
'title' => sprintf(_('%s timeline'), $this->target->getNickname()),
|
||||||
'link' => common_local_url('showgroup', array('nickname' => $group->nickname)),
|
'link' => common_local_url('showgroup', array('nickname' => $this->target->getNickname())),
|
||||||
// TRANS: Message is used as link description. %1$s is a group name, %2$s is a site name.
|
// TRANS: Message is used as link description. %1$s is a group name, %2$s is a site name.
|
||||||
'description' => sprintf(_('Updates from members of %1$s on %2$s!'),
|
'description' => sprintf(_('Updates from members of %1$s on %2$s!'),
|
||||||
$group->nickname, common_config('site', 'name')));
|
$this->target->getNickname(), common_config('site', 'name')));
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,7 @@
|
|||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings for Jabber/XMPP integration
|
* Settings for Jabber/XMPP integration
|
||||||
@@ -118,8 +116,8 @@ class ImsettingsAction extends SettingsAction
|
|||||||
// TRANS: Button label to remove a confirmed IM address.
|
// TRANS: Button label to remove a confirmed IM address.
|
||||||
$this->submit('remove', _m('BUTTON','Remove'));
|
$this->submit('remove', _m('BUTTON','Remove'));
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$confirm = $this->getConfirmation($transport);
|
$confirm = $this->getConfirmation($transport);
|
||||||
if ($confirm) {
|
|
||||||
$this->element('p', 'form_unconfirmed', $confirm->address);
|
$this->element('p', 'form_unconfirmed', $confirm->address);
|
||||||
// TRANS: Form note in IM settings form.
|
// TRANS: Form note in IM settings form.
|
||||||
$this->element('p', 'form_note',
|
$this->element('p', 'form_note',
|
||||||
@@ -134,7 +132,7 @@ class ImsettingsAction extends SettingsAction
|
|||||||
$this->hidden('screenname', $confirm->address);
|
$this->hidden('screenname', $confirm->address);
|
||||||
// TRANS: Button label to cancel an IM address confirmation procedure.
|
// TRANS: Button label to cancel an IM address confirmation procedure.
|
||||||
$this->submit('cancel', _m('BUTTON','Cancel'));
|
$this->submit('cancel', _m('BUTTON','Cancel'));
|
||||||
} else {
|
} catch (NoResultException $e) {
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
// TRANS: Field label for IM address.
|
// TRANS: Field label for IM address.
|
||||||
@@ -179,8 +177,6 @@ class ImsettingsAction extends SettingsAction
|
|||||||
// TRANS: Checkbox label in IM preferences form.
|
// TRANS: Checkbox label in IM preferences form.
|
||||||
array('name'=>'replies', 'description'=>_('Send me replies '.
|
array('name'=>'replies', 'description'=>_('Send me replies '.
|
||||||
'from people I\'m not subscribed to.')),
|
'from people I\'m not subscribed to.')),
|
||||||
// TRANS: Checkbox label in IM preferences form.
|
|
||||||
array('name'=>'microid', 'description'=>_('Publish a MicroID'))
|
|
||||||
);
|
);
|
||||||
foreach($preferences as $preference)
|
foreach($preferences as $preference)
|
||||||
{
|
{
|
||||||
@@ -211,57 +207,35 @@ class ImsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function getConfirmation($transport)
|
function getConfirmation($transport)
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$confirm = new Confirm_address();
|
$confirm = new Confirm_address();
|
||||||
|
|
||||||
$confirm->user_id = $user->id;
|
$confirm->user_id = $this->scoped->getID();
|
||||||
$confirm->address_type = $transport;
|
$confirm->address_type = $transport;
|
||||||
|
|
||||||
if ($confirm->find(true)) {
|
if ($confirm->find(true)) {
|
||||||
return $confirm;
|
return $confirm;
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
throw new NoResultException($confirm);
|
||||||
* Handle posts to this form
|
}
|
||||||
*
|
|
||||||
* Based on the button that was pressed, muxes out to other functions
|
protected function doPost()
|
||||||
* to do the actual task requested.
|
|
||||||
*
|
|
||||||
* All sub-functions reload the form with a message -- success or failure.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function handlePost()
|
|
||||||
{
|
{
|
||||||
// CSRF protection
|
|
||||||
$token = $this->trimmed('token');
|
|
||||||
if (!$token || $token != common_session_token()) {
|
|
||||||
// TRANS: Client error displayed when the session token does not match or is not given.
|
|
||||||
$this->showForm(_('There was a problem with your session token. '.
|
|
||||||
'Try again, please.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->arg('save')) {
|
if ($this->arg('save')) {
|
||||||
$this->savePreferences();
|
return $this->savePreferences();
|
||||||
} else if ($this->arg('add')) {
|
} else if ($this->arg('add')) {
|
||||||
$this->addAddress();
|
return $this->addAddress();
|
||||||
} else if ($this->arg('cancel')) {
|
} else if ($this->arg('cancel')) {
|
||||||
$this->cancelConfirmation();
|
return $this->cancelConfirmation();
|
||||||
} else if ($this->arg('remove')) {
|
} else if ($this->arg('remove')) {
|
||||||
$this->removeAddress();
|
return $this->removeAddress();
|
||||||
} else {
|
|
||||||
// TRANS: Message given submitting a form with an unknown action in Instant Messaging settings.
|
|
||||||
$this->showForm(_('Unexpected form submission.'));
|
|
||||||
}
|
}
|
||||||
|
// TRANS: Message given submitting a form with an unknown action in Instant Messaging settings.
|
||||||
|
throw new ClientException(_('Unexpected form submission.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save user's Jabber preferences
|
* Save user's XMPP preferences
|
||||||
*
|
*
|
||||||
* These are the checkboxes at the bottom of the page. They're used to
|
* These are the checkboxes at the bottom of the page. They're used to
|
||||||
* set different settings
|
* set different settings
|
||||||
@@ -270,14 +244,12 @@ class ImsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function savePreferences()
|
function savePreferences()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$user_im_prefs = new User_im_prefs();
|
$user_im_prefs = new User_im_prefs();
|
||||||
$user_im_prefs->query('BEGIN');
|
$user_im_prefs->query('BEGIN');
|
||||||
$user_im_prefs->user_id = $user->id;
|
$user_im_prefs->user_id = $this->scoped->getID();
|
||||||
if($user_im_prefs->find() && $user_im_prefs->fetch())
|
if($user_im_prefs->find() && $user_im_prefs->fetch())
|
||||||
{
|
{
|
||||||
$preferences = array('notify', 'updatefrompresence', 'replies', 'microid');
|
$preferences = array('notify', 'updatefrompresence', 'replies');
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
$original = clone($user_im_prefs);
|
$original = clone($user_im_prefs);
|
||||||
@@ -289,15 +261,15 @@ class ImsettingsAction extends SettingsAction
|
|||||||
$result = $new->update($original);
|
$result = $new->update($original);
|
||||||
|
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
common_log_db_error($user_im_prefs, 'UPDATE', __FILE__);
|
||||||
// TRANS: Server error thrown on database error updating IM preferences.
|
// TRANS: Server error thrown on database error updating IM preferences.
|
||||||
$this->serverError(_('Could not update IM preferences.'));
|
throw new ServerException(_('Could not update IM preferences.'));
|
||||||
}
|
}
|
||||||
}while($user_im_prefs->fetch());
|
}while($user_im_prefs->fetch());
|
||||||
}
|
}
|
||||||
$user_im_prefs->query('COMMIT');
|
$user_im_prefs->query('COMMIT');
|
||||||
// TRANS: Confirmation message for successful IM preferences save.
|
// TRANS: Confirmation message for successful IM preferences save.
|
||||||
$this->showForm(_('Preferences saved.'), true);
|
return _('Preferences saved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,49 +282,42 @@ class ImsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function addAddress()
|
function addAddress()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$screenname = $this->trimmed('screenname');
|
$screenname = $this->trimmed('screenname');
|
||||||
$transport = $this->trimmed('transport');
|
$transport = $this->trimmed('transport');
|
||||||
|
|
||||||
// Some validation
|
// Some validation
|
||||||
|
|
||||||
if (!$screenname) {
|
if (empty($screenname)) {
|
||||||
// TRANS: Message given saving IM address without having provided one.
|
// TRANS: Message given saving IM address without having provided one.
|
||||||
$this->showForm(_('No screenname.'));
|
throw new ClientException(_('No screenname.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$transport) {
|
if (empty($transport)) {
|
||||||
// TRANS: Form validation error when no transport is available setting an IM address.
|
// TRANS: Form validation error when no transport is available setting an IM address.
|
||||||
$this->showForm(_('No transport.'));
|
throw new ClientException(_('No transport.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::handle('NormalizeImScreenname', array($transport, &$screenname));
|
Event::handle('NormalizeImScreenname', array($transport, &$screenname));
|
||||||
|
|
||||||
if (!$screenname) {
|
if (empty($screenname)) {
|
||||||
// TRANS: Message given saving IM address that cannot be normalised.
|
// TRANS: Message given saving IM address that cannot be normalised.
|
||||||
$this->showForm(_('Cannot normalize that screenname.'));
|
throw new ClientException(_('Cannot normalize that screenname.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
$valid = false;
|
$valid = false;
|
||||||
Event::handle('ValidateImScreenname', array($transport, $screenname, &$valid));
|
Event::handle('ValidateImScreenname', array($transport, $screenname, &$valid));
|
||||||
if (!$valid) {
|
if (!$valid) {
|
||||||
// TRANS: Message given saving IM address that not valid.
|
// TRANS: Message given saving IM address that not valid.
|
||||||
$this->showForm(_('Not a valid screenname.'));
|
throw new ClientException(_('Not a valid screenname.'));
|
||||||
return;
|
|
||||||
} else if ($this->screennameExists($transport, $screenname)) {
|
} else if ($this->screennameExists($transport, $screenname)) {
|
||||||
// TRANS: Message given saving IM address that is already set for another user.
|
// TRANS: Message given saving IM address that is already set for another user.
|
||||||
$this->showForm(_('Screenname already belongs to another user.'));
|
throw new ClientException(_('Screenname already belongs to another user.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$confirm = new Confirm_address();
|
$confirm = new Confirm_address();
|
||||||
|
|
||||||
$confirm->address = $screenname;
|
$confirm->address = $screenname;
|
||||||
$confirm->address_type = $transport;
|
$confirm->address_type = $transport;
|
||||||
$confirm->user_id = $user->id;
|
$confirm->user_id = $this->scoped->getID();
|
||||||
$confirm->code = common_confirmation_code(64);
|
$confirm->code = common_confirmation_code(64);
|
||||||
$confirm->sent = common_sql_now();
|
$confirm->sent = common_sql_now();
|
||||||
$confirm->claimed = common_sql_now();
|
$confirm->claimed = common_sql_now();
|
||||||
@@ -365,13 +330,10 @@ class ImsettingsAction extends SettingsAction
|
|||||||
$this->serverError(_('Could not insert confirmation code.'));
|
$this->serverError(_('Could not insert confirmation code.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::handle('SendImConfirmationCode', array($transport, $screenname, $confirm->code, $user));
|
Event::handle('SendImConfirmationCode', array($transport, $screenname, $confirm->code, $this->scoped));
|
||||||
|
|
||||||
// TRANS: Message given saving valid IM address that is to be confirmed.
|
// TRANS: Message given saving valid IM address that is to be confirmed.
|
||||||
$msg = _('A confirmation code was sent '.
|
return _('A confirmation code was sent to the IM address you added.');
|
||||||
'to the IM address you added.');
|
|
||||||
|
|
||||||
$this->showForm($msg, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -386,29 +348,21 @@ class ImsettingsAction extends SettingsAction
|
|||||||
$screenname = $this->trimmed('screenname');
|
$screenname = $this->trimmed('screenname');
|
||||||
$transport = $this->trimmed('transport');
|
$transport = $this->trimmed('transport');
|
||||||
|
|
||||||
|
try {
|
||||||
$confirm = $this->getConfirmation($transport);
|
$confirm = $this->getConfirmation($transport);
|
||||||
|
|
||||||
if (!$confirm) {
|
|
||||||
// TRANS: Message given canceling Instant Messaging address confirmation that is not pending.
|
|
||||||
$this->showForm(_('No pending confirmation to cancel.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($confirm->address != $screenname) {
|
if ($confirm->address != $screenname) {
|
||||||
// TRANS: Message given canceling IM address confirmation for the wrong IM address.
|
// TRANS: Message given canceling IM address confirmation for the wrong IM address.
|
||||||
$this->showForm(_('That is the wrong IM address.'));
|
throw new ClientException(_('That is the wrong IM address.'));
|
||||||
return;
|
}
|
||||||
|
} catch (NoResultException $e) {
|
||||||
|
// TRANS: Message given canceling Instant Messaging address confirmation that is not pending.
|
||||||
|
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $confirm->delete();
|
$confirm->delete();
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
common_log_db_error($confirm, 'DELETE', __FILE__);
|
|
||||||
// TRANS: Server error thrown on database error canceling IM address confirmation.
|
|
||||||
$this->serverError(_('Could not delete confirmation.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TRANS: Message given after successfully canceling IM address confirmation.
|
// TRANS: Message given after successfully canceling IM address confirmation.
|
||||||
$this->showForm(_('IM confirmation cancelled.'), true);
|
return _('IM confirmation cancelled.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -420,34 +374,32 @@ class ImsettingsAction extends SettingsAction
|
|||||||
*/
|
*/
|
||||||
function removeAddress()
|
function removeAddress()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$screenname = $this->trimmed('screenname');
|
$screenname = $this->trimmed('screenname');
|
||||||
$transport = $this->trimmed('transport');
|
$transport = $this->trimmed('transport');
|
||||||
|
|
||||||
// Maybe an old tab open...?
|
// Maybe an old tab open...?
|
||||||
|
|
||||||
$user_im_prefs = new User_im_prefs();
|
$user_im_prefs = new User_im_prefs();
|
||||||
$user_im_prefs->user_id = $user->id;
|
$user_im_prefs->user_id = $this->scoped->getID();
|
||||||
if(! ($user_im_prefs->find() && $user_im_prefs->fetch())) {
|
$user_im_prefs->transport = $transport;
|
||||||
|
if (!$user_im_prefs->find(true)) {
|
||||||
// TRANS: Message given trying to remove an IM address that is not
|
// TRANS: Message given trying to remove an IM address that is not
|
||||||
// TRANS: registered for the active user.
|
// TRANS: registered for the active user.
|
||||||
$this->showForm(_('That is not your screenname.'));
|
throw new AlreadyFulfilledException(_('There were no preferences stored for this transport.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $user_im_prefs->delete();
|
$result = $user_im_prefs->delete();
|
||||||
|
|
||||||
if (!$result) {
|
if ($result === false) {
|
||||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
common_log_db_error($user_im_prefs, 'UPDATE', __FILE__);
|
||||||
// TRANS: Server error thrown on database error removing a registered IM address.
|
// TRANS: Server error thrown on database error removing a registered IM address.
|
||||||
$this->serverError(_('Could not update user IM preferences.'));
|
throw new ServerException(_('Could not update user IM preferences.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: unsubscribe to the old address
|
// XXX: unsubscribe to the old address
|
||||||
|
|
||||||
// TRANS: Message given after successfully removing a registered Instant Messaging address.
|
// TRANS: Message given after successfully removing a registered Instant Messaging address.
|
||||||
$this->showForm(_('The IM address was removed.'), true);
|
return _('The IM address was removed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -463,15 +415,9 @@ class ImsettingsAction extends SettingsAction
|
|||||||
|
|
||||||
function screennameExists($transport, $screenname)
|
function screennameExists($transport, $screenname)
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$user_im_prefs = new User_im_prefs();
|
$user_im_prefs = new User_im_prefs();
|
||||||
$user_im_prefs->transport = $transport;
|
$user_im_prefs->transport = $transport;
|
||||||
$user_im_prefs->screenname = $screenname;
|
$user_im_prefs->screenname = $screenname;
|
||||||
if($user_im_prefs->find() && $user_im_prefs->fetch()){
|
return $user_im_prefs->find(true) ? true : false;
|
||||||
return true;
|
|
||||||
}else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.'));
|
||||||
@@ -118,7 +118,7 @@ class InviteAction extends Action
|
|||||||
$this->already[] = $other;
|
$this->already[] = $other;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
Subscription::start($profile, $other);
|
Subscription::ensureStart($profile, $other);
|
||||||
$this->subbed[] = $other;
|
$this->subbed[] = $other;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// subscription failed, but keep working
|
// subscription failed, but keep working
|
||||||
|
|||||||
@@ -36,24 +36,6 @@ class LoginAction extends FormAction
|
|||||||
{
|
{
|
||||||
protected $needLogin = false;
|
protected $needLogin = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare page to run
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param $args
|
|
||||||
* @return string title
|
|
||||||
*/
|
|
||||||
protected function prepare(array $args=array())
|
|
||||||
{
|
|
||||||
// @todo this check should really be in index.php for all sensitive actions
|
|
||||||
$ssl = common_config('site', 'ssl');
|
|
||||||
if (empty($_SERVER['HTTPS']) && ($ssl == 'always' || $ssl == 'sometimes')) {
|
|
||||||
common_redirect(common_local_url('login'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::prepare($args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle input, produce output
|
* Handle input, produce output
|
||||||
*
|
*
|
||||||
@@ -79,10 +61,8 @@ class LoginAction extends FormAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function handlePost()
|
protected function doPost()
|
||||||
{
|
{
|
||||||
parent::handlePost();
|
|
||||||
|
|
||||||
// XXX: login throttle
|
// XXX: login throttle
|
||||||
|
|
||||||
$nickname = $this->trimmed('nickname');
|
$nickname = $this->trimmed('nickname');
|
||||||
@@ -122,22 +102,6 @@ class LoginAction extends FormAction
|
|||||||
common_redirect($url, 303);
|
common_redirect($url, 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Store an error and show the page
|
|
||||||
*
|
|
||||||
* This used to show the whole page; now, it's just a wrapper
|
|
||||||
* that stores the error in an attribute.
|
|
||||||
*
|
|
||||||
* @param string $error error, if any.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function showForm($msg=null, $success=false)
|
|
||||||
{
|
|
||||||
common_ensure_session();
|
|
||||||
return parent::showForm($msg, $success);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showScripts()
|
function showScripts()
|
||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
@@ -208,7 +172,7 @@ class LoginAction extends FormAction
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function getInstructions()
|
protected function getInstructions()
|
||||||
{
|
{
|
||||||
if (common_logged_in() && !common_is_real_login() &&
|
if (common_logged_in() && !common_is_real_login() &&
|
||||||
common_get_returnto()) {
|
common_get_returnto()) {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class LogoutAction extends ManagedAction
|
|||||||
}
|
}
|
||||||
Event::handle('EndLogout', array($this));
|
Event::handle('EndLogout', array($this));
|
||||||
|
|
||||||
common_redirect(common_local_url('startpage'));
|
common_redirect(common_local_url('top'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessed through the action on events
|
// Accessed through the action on events
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user