Comparar commits
1212 Commits
1.1.x
..
v1.2.0beta4
| Autor | SHA1 | Data | |
|---|---|---|---|
| b2cfbded2e | |||
| 346a73c36f | |||
| 6336248d71 | |||
| 67aff528f5 | |||
| 80f7a5f025 | |||
| e6f07d8554 | |||
| 31c9b2c1d8 | |||
| 9319033ff0 | |||
| 0eb5122817 | |||
| 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 | |||
| 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 | |||
| 67dfc0a046 | |||
| b9d35659c8 | |||
| 733debd9b3 | |||
| 8806cce735 | |||
| dd229e855a | |||
| 893d888152 | |||
| 49b7648fea | |||
| d0b2d86ca1 | |||
| 9f961597c6 | |||
| a61235086b | |||
| ec257d940a | |||
| dcf29c2a07 | |||
| eaa394ed7d | |||
| 7c90d7022b | |||
| ef5ed10eb9 | |||
| cd71188d3a | |||
| a30d34be7f | |||
| d98784e059 | |||
| 3dea259f52 | |||
| 2938b3e960 | |||
| 13cf744fb3 | |||
| 2686635f60 | |||
| 1126f70786 | |||
| 7c7f2f890f | |||
| d6664f5735 | |||
| 58e852f7f7 | |||
| 6bec22ea4e | |||
| 25f623565a | |||
| 098c8b1df4 | |||
| 55546a5aab | |||
| 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 | |||
| 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 | |||
| 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 |
@@ -1,5 +1,4 @@
|
||||
avatar/*
|
||||
background/*
|
||||
files/*
|
||||
file/*
|
||||
local/*
|
||||
|
||||
+9
-31
@@ -100,6 +100,10 @@ ssl: Whether to use SSL and https:// URLs for some or all pages.
|
||||
(don't use it for any pages), or 'sometimes' (use it for
|
||||
sensitive pages that include passwords like login and registration,
|
||||
but not for regular pages). Default to 'never'.
|
||||
sslproxy: Whether to force GNUsocial to think it is HTTPS when the
|
||||
server gives no such information. I.e. when you're using a reverse
|
||||
proxy that adds the encryption layer but the webserver that runs PHP
|
||||
isn't configured with a key and certificate.
|
||||
sslserver: use an alternate server name for SSL URLs, like
|
||||
'secure.example.org'. You should be careful to set cookie
|
||||
parameters correctly so that both the SSL server and the
|
||||
@@ -563,6 +567,11 @@ sslserver: if specified, this server will be used when creating HTTPS
|
||||
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
|
||||
-----
|
||||
@@ -601,23 +610,6 @@ handle: boolean. Whether we should register our own PHP session-handling
|
||||
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
|
||||
----
|
||||
|
||||
@@ -627,20 +619,6 @@ 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
|
||||
------
|
||||
|
||||
|
||||
+36
-2
@@ -2,6 +2,13 @@ InitializePlugin: a chance to initialize a plugin in a complete environment
|
||||
|
||||
CleanupPlugin: a chance to cleanup a plugin at the end of a program
|
||||
|
||||
StartActionExecute: Right before the "prepare" call of the current Action
|
||||
- $action: the current Action object
|
||||
- &$args: array of arguments, referenced so you can modify the array
|
||||
|
||||
EndActionExecute: Right after the "handle" call of the current Action
|
||||
- $action: the current Action object
|
||||
|
||||
StartPrimaryNav: Showing the primary nav menu
|
||||
- $action: the current action
|
||||
|
||||
@@ -608,12 +615,12 @@ EndCheckPassword: After checking a username/password pair
|
||||
- $authenticatedUser: User object if credentials match a user, else null.
|
||||
|
||||
StartChangePassword: Before changing a password
|
||||
- $user: user
|
||||
- Profile $target: The profile of the User that is changing password
|
||||
- $oldpassword: the user's old password
|
||||
- $newpassword: the desired new password
|
||||
|
||||
EndChangePassword: After changing a password
|
||||
- $user: user
|
||||
- Profile $target: The profile of the User that just changed its password
|
||||
|
||||
StartHashPassword: Generate a hashed version of the password (like a salted crypt)
|
||||
- &$hashed: Hashed version of the password, later put in the database
|
||||
@@ -1444,6 +1451,9 @@ StartResizeImageFile: Hook to resize an image and output it to a file. No matchi
|
||||
- $outpath: string with output filepath
|
||||
- $box: array with size ('width', 'height') and boundary box('x', 'y', 'w', 'h').
|
||||
|
||||
FillImageFileMetadata: Get more metadata about the ImageFile if it is perhaps not a real local file
|
||||
- $imagefile ImageFile object which we're getting metadata for (such as animated status, width/height etc.)
|
||||
|
||||
StartShowAttachmentRepresentation: Attachment representation, full file (or in rare cases thumbnails/previews).
|
||||
- $out: HTMLOutputter class to use for outputting HTML.
|
||||
- $file: 'File' object which we're going to show representation for.
|
||||
@@ -1463,3 +1473,27 @@ StartNotifyMentioned: During notice distribution, we send notifications (email,
|
||||
EndNotifyMentioned: During notice distribution, we send notifications (email, im...) to the profiles who were somehow mentioned.
|
||||
- $stored: Notice object that is being distributed.
|
||||
- $mentioned_ids: Array of profile IDs (not just for local users) who got mentioned by the notice.
|
||||
|
||||
StartHomeStubNavItems: Go back Home nav items. Default includes just one item 'home'
|
||||
- $out: HTMLOutputter used to output (usually an Action, but not always!)
|
||||
- &$items: Referenced array of items in the nav (add if desired)
|
||||
|
||||
EndHomeStubNavItems:
|
||||
- $out: HTMLOutputter used to output (usually an Action, but not always!)
|
||||
- $items: array of menu items
|
||||
|
||||
StartSubMenu: Before outputting a submenu (including enclosing tags) to HTML
|
||||
- $out: HTMLOutputter used to output (usually an Action, but not always!)
|
||||
- $menu: The Menu object outputted as a submenu.
|
||||
- $label: Localized text which represents the menu item.
|
||||
|
||||
EndSubMenu: After outputting a submenu (including enclosing tags) to HTML
|
||||
- $out: HTMLOutputter used to output (usually an Action, but not always!)
|
||||
- $menu: The Menu object outputted as a submenu.
|
||||
- $label: Localized text which represents the menu item.
|
||||
|
||||
StartDocNav: Before outputting the docs Nav
|
||||
- $nav: The DoclNav widget
|
||||
|
||||
EndDocNav: After outputting the docs Nav
|
||||
- $nav: The DoclNav widget
|
||||
|
||||
+129
-131
@@ -6,13 +6,16 @@ TABLE OF CONTENTS
|
||||
* Installation
|
||||
- Getting it up and running
|
||||
- Fancy URLs
|
||||
- Themes
|
||||
- Private
|
||||
* Extra features
|
||||
- Sphinx
|
||||
- SMS
|
||||
- Queues and daemons
|
||||
- Themes
|
||||
- Translation
|
||||
- Queues and daemons
|
||||
* After installation
|
||||
- Backups
|
||||
- Private
|
||||
- Upgrading
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
@@ -23,7 +26,7 @@ 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
|
||||
- PHP 5.5+ 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
|
||||
@@ -41,9 +44,10 @@ functional setup of GNU Social:
|
||||
- php5-curl Fetching files by HTTP.
|
||||
- php5-gd Image manipulation (scaling).
|
||||
- php5-gmp For Salmon signatures (part of OStatus).
|
||||
- php5-intl Internationalization support (transliteration et al).
|
||||
- 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.
|
||||
use MySQL, 'php5-mysql' or 'php5-mysqli' may be enough.
|
||||
|
||||
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
|
||||
@@ -68,7 +72,7 @@ For some functionality, you will also need the following extensions:
|
||||
|
||||
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.
|
||||
Enable it in your php.ini where it is documented together with its settings.
|
||||
|
||||
Installation
|
||||
============
|
||||
@@ -105,11 +109,13 @@ especially if you've previously installed PHP/MariaDB packages.
|
||||
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.
|
||||
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 probably work:
|
||||
On some systems, this will work as a more secure alternative:
|
||||
|
||||
chgrp www-data /var/www/gnusocial/
|
||||
chmod g+w /var/www/gnusocial/
|
||||
@@ -118,21 +124,20 @@ especially if you've previously installed PHP/MariaDB packages.
|
||||
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
|
||||
4. You should also take this moment to make your 'avatar' and 'file' sub-
|
||||
directories writeable by the Web server. The _insecure_ way to do
|
||||
this is:
|
||||
|
||||
chmod a+w /var/www/gnusocial/avatar
|
||||
chmod a+w /var/www/gnusocial/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.
|
||||
You can also make the avatar, and file directories just writable by
|
||||
the Web server group, as noted above.
|
||||
|
||||
5. Create a database to hold your site data. Something like this
|
||||
should work:
|
||||
should work (you will be prompted for your database password):
|
||||
|
||||
mysqladmin -u "root" --password="rootpassword" create gnusocial
|
||||
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,
|
||||
@@ -146,17 +151,17 @@ especially if you've previously installed PHP/MariaDB packages.
|
||||
database. If you have shell access, this will probably work from the
|
||||
MariaDB shell:
|
||||
|
||||
GRANT ALL on gnusocial.*
|
||||
TO 'gnusocial'@'localhost'
|
||||
GRANT ALL on social.*
|
||||
TO 'social'@'localhost'
|
||||
IDENTIFIED BY 'agoodpassword';
|
||||
|
||||
You should change the user identifier 'gnusocial' and '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.
|
||||
|
||||
7. In a browser, navigate to the GNU Social install script; something like:
|
||||
|
||||
http://social.example.net/install.php
|
||||
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,
|
||||
@@ -170,55 +175,102 @@ 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:
|
||||
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:
|
||||
|
||||
http://example.net/gnusocial/index.php/gnusocial/fred
|
||||
https://social.example.net/index.php/fred
|
||||
https://social.example.net/index.php?p=fred
|
||||
|
||||
On certain systems that don't support this kind of syntax, they'll
|
||||
look like this:
|
||||
It's possible to configure the software to use fancy URLs so it looks like
|
||||
this instead:
|
||||
|
||||
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
|
||||
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. 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:
|
||||
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:
|
||||
|
||||
http://example.net/gnusocial/main/register
|
||||
https://social.example.net/main/register
|
||||
|
||||
If you changed your HTTP server configuration, you may need to restart
|
||||
the server first.
|
||||
Themes
|
||||
------
|
||||
|
||||
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:
|
||||
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.
|
||||
|
||||
http://httpd.apache.org/docs/2.2/howto/htaccess.html
|
||||
You can choose a theme using the $config['site']['theme'] element in
|
||||
the config.php file. See below for details.
|
||||
|
||||
Also, check that mod_rewrite is installed and enabled:
|
||||
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:
|
||||
|
||||
http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html
|
||||
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
|
||||
------
|
||||
@@ -283,7 +335,21 @@ For this to work, there *must* be a domain or sub-domain for which all
|
||||
|
||||
$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
|
||||
------------------
|
||||
@@ -300,12 +366,12 @@ Two mechanisms are available to achieve offline operations:
|
||||
### 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.
|
||||
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).
|
||||
|
||||
Each time it can, OpportunisticQM will try to handle some of them.
|
||||
Whenever it has time, OpportunisticQM will try to handle some of them.
|
||||
|
||||
This is a good solution whether you:
|
||||
|
||||
@@ -345,16 +411,13 @@ separate server is probably a good idea for high-volume sites.
|
||||
.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:
|
||||
3. In your config.php files (on the server where you run the queue
|
||||
daemon), 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.
|
||||
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.
|
||||
|
||||
@@ -384,85 +447,20 @@ 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
|
||||
After installation
|
||||
==================
|
||||
|
||||
Backups
|
||||
-------
|
||||
|
||||
There is no built-in system for doing backups in StatusNet. You can make
|
||||
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 <http://ur1.ca/7xo>
|
||||
the Web directory. To backup the database use mysqldump <https://mariadb.com/kb/en/mariadb/mysqldump/>
|
||||
and to backup the Web directory, try tar.
|
||||
|
||||
Private
|
||||
-------
|
||||
Upgrading
|
||||
---------
|
||||
|
||||
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';
|
||||
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.
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
Plugins
|
||||
=======
|
||||
|
||||
Beginning with the 0.7.x branch, StatusNet has supported a simple but
|
||||
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
|
||||
@@ -37,7 +37,7 @@ can enable a plugin with the following line in config.php:
|
||||
|
||||
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 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/.
|
||||
|
||||
|
||||
+13
-9
@@ -1,5 +1,5 @@
|
||||
# GNU social 1.1.3
|
||||
February 2015-02-27
|
||||
# GNU social 1.2.x
|
||||
2015
|
||||
|
||||
(c) Free Software Foundation, Inc
|
||||
(c) StatusNet, Inc
|
||||
@@ -100,15 +100,19 @@ for additional terms.
|
||||
|
||||
## New this version
|
||||
|
||||
This is a security fix and bug fix release since 1.1.3-beta2.
|
||||
All 1.1.x sites should upgrade to this version.
|
||||
This is the development branch for the 1.2.x version of GNU social.
|
||||
All daring 1.1.x admins should upgrade to this version.
|
||||
|
||||
So far it includes the following changes:
|
||||
|
||||
- Backing up a user's account is more and more complete.
|
||||
- Emojis 😸 (utf8mb4 support)
|
||||
|
||||
The last release, 1.1.3, gave us these improvements:
|
||||
|
||||
- XSS security fix (thanks Simon Waters, <https://www.surevine.com/>)
|
||||
- Many improvements to ease adoption of the Qvitter front-end <https://github.com/hannesmannerheim/qvitter>
|
||||
- Protocol adaptions for improved performance and stability
|
||||
- Backing up a user's account now appears to work as it should
|
||||
|
||||
Upgrades from _StatusNet_ 1.1.1 will also experience these improvements:
|
||||
|
||||
@@ -140,13 +144,13 @@ to install the development version of GNU social.
|
||||
To get it, use the git version control tool
|
||||
<http://git-scm.com/> like so:
|
||||
|
||||
git clone git@gitorious.org:social/mainline.git
|
||||
git clone git@git.gnu.io:gnu/gnu-social.git
|
||||
|
||||
In the current phase of development it is probably
|
||||
recommended to use git as a means to stay up to date
|
||||
with the source code. You can choose between these
|
||||
branches:
|
||||
- 1.1.x "stable", few updates, well tested code
|
||||
- 1.2.x "stable", few updates, well tested code
|
||||
- master "testing", more updates, usually working well
|
||||
- nightly "unstable", most updates, not always working
|
||||
|
||||
@@ -162,8 +166,8 @@ There are several ways to get more information about GNU 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
|
||||
making things better. <https://bugz.foocorp.net/>
|
||||
* Patches are welcome, preferrably to our repository on Gitorious. <https://gitorious.org/social/mainline>
|
||||
making things better. <https://git.gnu.io/gnu/gnu-social/issues/>
|
||||
* Patches are welcome, preferrably to our repository on git.gnu.io. <https://git.gnu.io/gnu/gnu-social>
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
+77
-79
@@ -1,99 +1,97 @@
|
||||
Upgrading
|
||||
=========
|
||||
|
||||
StatusNet 1.1.1 to GNU social
|
||||
-----------------------------
|
||||
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).
|
||||
|
||||
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.
|
||||
Beware there may be changes in minimum required version of PHP and the
|
||||
modules used, so double-check the INSTALL file's requirements list.
|
||||
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
|
||||
* 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.
|
||||
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. 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:
|
||||
1. Stop your queue daemons 'bash scripts/stopdaemons.sh' should do it.
|
||||
Not everyone runs queue daemons, but the above command won't hurt.
|
||||
|
||||
avatar/*
|
||||
background/*
|
||||
file/*
|
||||
local/*
|
||||
.htaccess
|
||||
config.php
|
||||
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. 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)
|
||||
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
|
||||
|
||||
Legacy StatusNet instructions
|
||||
-----------------------------
|
||||
This command will point you in the right direction on how to do it:
|
||||
$ rsync -avP statusnet/{.htaccess,avatar,file,local,config.php} gnusocial/
|
||||
|
||||
These instructions are here for historical and perhaps informational
|
||||
purposes.
|
||||
4. Replace your old StatusNet directory with the new GNU social
|
||||
directory in your webserver root.
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
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.
|
||||
6. Start your queue daemons: 'bash scripts/startdaemons.sh'
|
||||
|
||||
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.
|
||||
7. Report any issues at https://git.gnu.io/gnu/gnu-social/issues
|
||||
|
||||
+20
-43
@@ -35,38 +35,24 @@
|
||||
* @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;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
public function getStream()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
if (!empty($user) && $user->streamModeOnly()) {
|
||||
if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
|
||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||
} else {
|
||||
$stream = new ThreadingInboxNoticeStream($this->target, $this->scoped);
|
||||
}
|
||||
|
||||
$this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
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;
|
||||
return $stream;
|
||||
}
|
||||
|
||||
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.
|
||||
return _('Home timeline');
|
||||
} else {
|
||||
@@ -83,44 +69,44 @@ class AllAction extends ProfileAction
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'as',
|
||||
'id' => $this->target->nickname
|
||||
'id' => $this->target->getNickname()
|
||||
)
|
||||
),
|
||||
// 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,
|
||||
common_local_url(
|
||||
'allrss', array(
|
||||
'nickname' =>
|
||||
$this->target->nickname)
|
||||
$this->target->getNickname())
|
||||
),
|
||||
// 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,
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'rss',
|
||||
'id' => $this->target->nickname
|
||||
'id' => $this->target->getNickname()
|
||||
)
|
||||
),
|
||||
// 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,
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'atom',
|
||||
'id' => $this->target->nickname
|
||||
'id' => $this->target->getNickname()
|
||||
)
|
||||
),
|
||||
// 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()
|
||||
{
|
||||
// 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 ($this->target->id === $this->scoped->id) {
|
||||
@@ -130,12 +116,12 @@ class AllAction extends ProfileAction
|
||||
} else {
|
||||
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@".
|
||||
// TRANS: This message contains Markdown links. Keep "](" together.
|
||||
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->target->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 {
|
||||
// TRANS: Encouragement displayed on empty timeline user pages for anonymous users.
|
||||
// TRANS: %s is a user nickname. This message contains Markdown links. Keep "](" together.
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->target->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');
|
||||
@@ -146,19 +132,10 @@ class AllAction extends ProfileAction
|
||||
function showContent()
|
||||
{
|
||||
if (Event::handle('StartShowAllContent', array($this))) {
|
||||
|
||||
$profile = null;
|
||||
|
||||
$current_user = common_current_user();
|
||||
|
||||
if (!empty($current_user)) {
|
||||
$profile = $current_user->getProfile();
|
||||
}
|
||||
|
||||
if (!empty($current_user) && $current_user->streamModeOnly()) {
|
||||
if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
|
||||
$nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
|
||||
} else {
|
||||
$nl = new ThreadedNoticeList($this->notice, $this, $profile);
|
||||
$nl = new ThreadedNoticeList($this->notice, $this, $this->scoped);
|
||||
}
|
||||
|
||||
$cnt = $nl->show();
|
||||
@@ -169,7 +146,7 @@ class AllAction extends ProfileAction
|
||||
|
||||
$this->pagination(
|
||||
$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));
|
||||
|
||||
+9
-69
@@ -28,11 +28,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AllrssAction extends Rss10Action
|
||||
class AllrssAction extends TargetedRss10Action
|
||||
{
|
||||
var $user = null;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if user doesn't exist
|
||||
*
|
||||
*/
|
||||
function prepare($args)
|
||||
protected function getNotices()
|
||||
{
|
||||
parent::prepare($args);
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$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;
|
||||
$stream = new InboxNoticeStream($this->target);
|
||||
return $stream->getNotices(0, $this->limit)->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,33 +57,17 @@ class AllrssAction extends Rss10Action
|
||||
*/
|
||||
function getChannel()
|
||||
{
|
||||
$user = $this->user;
|
||||
$c = array('url' => common_local_url('allrss',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
$this->target->getNickname())),
|
||||
// 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',
|
||||
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.
|
||||
'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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,9 +31,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* We don't have a rate limit, but some clients check this method.
|
||||
@@ -58,9 +56,9 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle($args);
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
@@ -69,7 +67,6 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$reset = new DateTime();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
@@ -132,9 +131,6 @@ class ApiAccountRegisterAction extends ApiAction
|
||||
!common_valid_http_url($homepage)) {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid homepage URL.
|
||||
$this->clientError(_('Homepage is not a valid URL.'), 400);
|
||||
} else if (!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)) {
|
||||
// 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.
|
||||
@@ -142,9 +138,6 @@ class ApiAccountRegisterAction extends ApiAction
|
||||
'Bio is too long (maximum %d characters).',
|
||||
Profile::maxBio()),
|
||||
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) {
|
||||
// TRANS: Form validation error displayed when trying to register with too short a password.
|
||||
$this->clientError(_('Password must be 6 or more characters.'), 400);
|
||||
@@ -152,34 +145,31 @@ class ApiAccountRegisterAction extends ApiAction
|
||||
// TRANS: Form validation error displayed when trying to register with non-matching passwords.
|
||||
$this->clientError(_('Passwords do not match.'), 400);
|
||||
} else {
|
||||
|
||||
// annoy spammers
|
||||
sleep(7);
|
||||
|
||||
if ($user = User::register(array('nickname' => $nickname,
|
||||
'password' => $password,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'bio' => $bio,
|
||||
'location' => $location,
|
||||
'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));
|
||||
// annoy spammers
|
||||
sleep(7);
|
||||
|
||||
if (Event::handle('APIStartRegistrationTry', array($this))) {
|
||||
try {
|
||||
$user = User::register(array('nickname' => $nickname,
|
||||
'password' => $password,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'bio' => $bio,
|
||||
'location' => $location,
|
||||
'code' => $this->code));
|
||||
Event::handle('EndRegistrationTry', array($this));
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->twitterUserArray($user->getProfile()));
|
||||
$this->endDocument('json');
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->twitterUserArray($user->getProfile()));
|
||||
$this->endDocument('json');
|
||||
|
||||
} else {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
|
||||
$this->clientError(_('Invalid username or password.'), 400);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,21 +96,12 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
|
||||
|
||||
$original = clone($profile);
|
||||
|
||||
if (!empty($this->name)) {
|
||||
$profile->fullname = $this->name;
|
||||
}
|
||||
|
||||
if (!empty($this->url)) {
|
||||
$profile->homepage = $this->url;
|
||||
}
|
||||
|
||||
if (!empty($this->description)) {
|
||||
$profile->bio = $this->description;
|
||||
}
|
||||
$profile->fullname = $this->name;
|
||||
$profile->homepage = $this->url;
|
||||
$profile->bio = $this->description;
|
||||
$profile->location = $this->location;
|
||||
|
||||
if (!empty($this->location)) {
|
||||
$profile->location = $this->location;
|
||||
|
||||
$loc = Location::fromName($this->location);
|
||||
|
||||
if (!empty($loc)) {
|
||||
@@ -119,6 +110,12 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
|
||||
$profile->location_id = $loc->location_id;
|
||||
$profile->location_ns = $loc->location_ns;
|
||||
}
|
||||
} else {
|
||||
// location is empty so reset the extrapolated information too
|
||||
$profile->lat = '';
|
||||
$profile->lon = '';
|
||||
$profile->location_id = '';
|
||||
$profile->location_ns = '';
|
||||
}
|
||||
|
||||
$result = $profile->update($original);
|
||||
|
||||
@@ -49,16 +49,9 @@ class ApiconversationAction extends ApiAuthAction
|
||||
protected $conversation = null;
|
||||
protected $notices = null;
|
||||
|
||||
/**
|
||||
* For initializing members of the class.
|
||||
*
|
||||
* @param array $argarray misc. arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function prepare($argarray)
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($argarray);
|
||||
parent::prepare($args);
|
||||
|
||||
$convId = $this->trimmed('id');
|
||||
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
if ($this->user->isSubscribed($this->other)) {
|
||||
if ($this->scoped->isSubscribed($this->other)) {
|
||||
$errmsg = sprintf(
|
||||
// TRANS: Client error displayed when trying to follow a user that's already being followed.
|
||||
// TRANS: %s is the nickname of the user that is already being followed.
|
||||
@@ -101,9 +99,9 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
|
||||
}
|
||||
|
||||
try {
|
||||
Subscription::start($this->user->getProfile(), $this->other);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), 403);
|
||||
Subscription::start($this->scoped, $this->other);
|
||||
} catch (AlreadyFulfilledException $e) {
|
||||
$this->clientError($e->getMessage(), 409);
|
||||
}
|
||||
|
||||
$this->initDocument($this->format);
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Allows the authenticating users to unfollow (unsubscribe) the user specified in
|
||||
@@ -48,7 +46,9 @@ if (!defined('STATUSNET')) {
|
||||
*/
|
||||
class ApiFriendshipsDestroyAction extends ApiAuthAction
|
||||
{
|
||||
var $other = null;
|
||||
protected $needPost = true;
|
||||
|
||||
protected $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
@@ -58,12 +58,11 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
function prepare($args)
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -73,58 +72,40 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
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;
|
||||
}
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
404
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->other)) {
|
||||
if (!$this->other instanceof Profile) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when trying to unfollow a user that cannot be found.
|
||||
_('Could not unfollow user: User not found.'),
|
||||
403,
|
||||
$this->format
|
||||
403
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow unsubscribing from yourself!
|
||||
|
||||
if ($this->user->id == $this->other->id) {
|
||||
if ($this->scoped->id == $this->other->id) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when trying to unfollow self.
|
||||
_("You cannot unfollow yourself."),
|
||||
403,
|
||||
$this->format
|
||||
403
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// throws an exception on error
|
||||
Subscription::cancel($this->user->getProfile(), $this->other);
|
||||
Subscription::cancel($this->scoped, $this->other);
|
||||
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function prepare($args)
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
@@ -72,22 +70,18 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle($args);
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->profile_a) || empty($this->profile_b)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
|
||||
_('Two valid IDs or nick names must be supplied.'),
|
||||
400,
|
||||
$this->format
|
||||
400
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Subscription::exists($this->profile_a, $this->profile_b);
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Outputs detailed information about the relationship between two users
|
||||
@@ -56,7 +54,7 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
@@ -109,13 +107,11 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle($args);
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
|
||||
@@ -115,11 +115,10 @@ class ApiListMembershipsAction extends ApiBareAuthAction
|
||||
|
||||
function getLists()
|
||||
{
|
||||
$profile = $this->target;
|
||||
$fn = array($profile, 'getOtherTags');
|
||||
$fn = array($this->target, 'getOtherTags');
|
||||
|
||||
# 20 lists
|
||||
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,
|
||||
$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)
|
||||
|
||||
+105
-28
@@ -30,7 +30,7 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @package StatusNet
|
||||
@@ -42,17 +42,20 @@ class ApiMediaUploadAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Grab the file from the 'media' param, then store, and shorten
|
||||
*
|
||||
* @todo Upload throttle!
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// fallback to xml for older clients etc
|
||||
if (empty($this->format)) {
|
||||
$this->format = 'xml';
|
||||
}
|
||||
if (!in_array($this->format, ['json', 'xml'])) {
|
||||
throw new ClientException('This API call does not support the format '._ve($this->format));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
@@ -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.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
throw new ClientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
|
||||
// we could catch "NoUploadedMediaException" as "no media uploaded", but here we _always_ want an upload
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
try {
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
common_debug('No media file was uploaded to the _FILES array');
|
||||
$fh = tmpfile();
|
||||
if ($this->arg('media')) {
|
||||
common_debug('Found media parameter which we hope contains a media file!');
|
||||
fwrite($fh, $this->arg('media'));
|
||||
} elseif ($this->arg('media_data')) {
|
||||
common_debug('Found media_data parameter which we hope contains a base64-encoded media file!');
|
||||
fwrite($fh, base64_decode($this->arg('media_data')));
|
||||
} else {
|
||||
common_debug('No media|media_data POST parameter was supplied');
|
||||
fclose($fh);
|
||||
throw $e;
|
||||
}
|
||||
common_debug('MediaFile importing the uploaded file with fromFilehandle');
|
||||
$upload = MediaFile::fromFilehandle($fh, $this->scoped);
|
||||
}
|
||||
|
||||
common_debug('MediaFile completed and saved us fileRecord with id=='._ve($upload->fileRecord->id));
|
||||
// Thumbnails will be generated/cached on demand when accessed (such as with /attachment/:id/thumbnail)
|
||||
|
||||
$this->showResponse($upload);
|
||||
}
|
||||
|
||||
@@ -88,14 +108,61 @@ class ApiMediaUploadAction extends ApiAuthAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showResponse(MediaFile $upload)
|
||||
protected function showResponse(MediaFile $upload)
|
||||
{
|
||||
$this->initDocument();
|
||||
$this->elementStart('rsp', array('stat' => 'ok'));
|
||||
$this->initDocument($this->format);
|
||||
switch ($this->format) {
|
||||
case 'json':
|
||||
return $this->showResponseJson($upload);
|
||||
case 'xml':
|
||||
return $this->showResponseXml($upload);
|
||||
default:
|
||||
throw new ClientException('This API call does not support the format '._ve($this->format));
|
||||
}
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
|
||||
protected function showResponseJson(MediaFile $upload)
|
||||
{
|
||||
$enc = $upload->fileRecord->getEnclosure();
|
||||
|
||||
// note that we use media_id instead of mediaid which XML users might've gotten used to (nowadays we service media_id in both!)
|
||||
$output = [
|
||||
'media_id' => $upload->fileRecord->id,
|
||||
'media_id_string' => (string)$upload->fileRecord->id,
|
||||
'media_url' => $upload->shortUrl(),
|
||||
'size' => $upload->fileRecord->size,
|
||||
];
|
||||
if (common_get_mime_media($enc->mimetype) === 'image') {
|
||||
$output['image'] = [
|
||||
'w' => $enc->width,
|
||||
'h' => $enc->height,
|
||||
'image_type' => $enc->mimetype,
|
||||
];
|
||||
}
|
||||
print json_encode($output);
|
||||
}
|
||||
|
||||
protected function showResponseXml(MediaFile $upload)
|
||||
{
|
||||
$this->elementStart('rsp', array('stat' => 'ok', 'xmlns:atom'=>Activity::ATOM));
|
||||
$this->element('mediaid', null, $upload->fileRecord->id);
|
||||
$this->element('mediaurl', null, $upload->shortUrl());
|
||||
$this->element('media_url', null, $upload->shortUrl());
|
||||
$this->element('size', null, $upload->fileRecord->size);
|
||||
|
||||
$enclosure = $upload->fileRecord->getEnclosure();
|
||||
$this->element('atom:link', array('rel' => 'enclosure',
|
||||
'href' => $enclosure->url,
|
||||
'type' => $enclosure->mimetype));
|
||||
|
||||
// Twitter specific metadata expected in response since Twitter's Media upload API v1.1 (even though Twitter doesn't use XML)
|
||||
$this->element('media_id', null, $upload->fileRecord->id);
|
||||
$this->element('media_id_string', null, (string)$upload->fileRecord->id);
|
||||
if (common_get_mime_media($enclosure->mimetype) === 'image') {
|
||||
$this->element('image', ['w'=>$enclosure->width, 'h'=>$enclosure->height, 'image_type'=>$enclosure->mimetype]);
|
||||
}
|
||||
$this->elementEnd('rsp');
|
||||
$this->endDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,16 +170,26 @@ class ApiMediaUploadAction extends ApiAuthAction
|
||||
*
|
||||
* @param String $msg an error message
|
||||
*/
|
||||
function clientError($msg)
|
||||
function clientError($msg, $code=400, $format=null)
|
||||
{
|
||||
$this->initDocument();
|
||||
$this->elementStart('rsp', array('stat' => 'fail'));
|
||||
$this->initDocument($this->format);
|
||||
switch ($this->format) {
|
||||
case 'json':
|
||||
$error = ['errors' => array()];
|
||||
$error['errors'][] = ['message'=>$msg, 'code'=>131];
|
||||
print json_encode($error);
|
||||
break;
|
||||
case 'xml':
|
||||
$this->elementStart('rsp', array('stat' => 'fail'));
|
||||
|
||||
// @todo add in error code
|
||||
$errAttr = array('msg' => $msg);
|
||||
// @todo add in error code
|
||||
$errAttr = array('msg' => $msg);
|
||||
|
||||
$this->element('err', $errAttr, null);
|
||||
$this->elementEnd('rsp');
|
||||
$this->endDocument();
|
||||
$this->element('err', $errAttr, null);
|
||||
$this->elementEnd('rsp');
|
||||
break;
|
||||
}
|
||||
$this->endDocument($this->format);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
|
||||
'rel' => 'alternate',
|
||||
'href' => $nurl));
|
||||
$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('link', array('type' => 'image/png',
|
||||
// XXX: Twitter uses rel="image" (not valid)
|
||||
|
||||
@@ -124,7 +124,7 @@ class ApiStatusesDestroyAction extends ApiAuthAction
|
||||
|
||||
if ($this->user->id == $this->notice->profile_id) {
|
||||
if (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) {
|
||||
$this->notice->delete();
|
||||
$this->notice->deleteAs($this->scoped);
|
||||
Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
|
||||
}
|
||||
$this->showNotice();
|
||||
|
||||
@@ -74,16 +74,21 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||
|
||||
$this->notice_id = (int)$this->trimmed('id');
|
||||
|
||||
$this->notice = Notice::getKV('id', $this->notice_id);
|
||||
if (!$this->notice instanceof Notice) {
|
||||
$deleted = Deleted_notice::getKV('id', $this->notice_id);
|
||||
if ($deleted instanceof Deleted_notice) {
|
||||
$this->notice = null;
|
||||
try {
|
||||
$this->notice = Notice::getByID($this->notice_id);
|
||||
} catch (NoResultException $e) {
|
||||
// No such notice was found, maybe it was deleted?
|
||||
$deleted = null;
|
||||
Event::handle('IsNoticeDeleted', array($this->notice_id, &$deleted));
|
||||
if ($deleted === true) {
|
||||
// TRANS: Client error displayed trying to show a deleted notice.
|
||||
$this->clientError(_('Notice deleted.'), 410);
|
||||
throw new ClientException(_('Notice deleted.'), 410);
|
||||
}
|
||||
// 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)) {
|
||||
// TRANS: Client exception thrown when trying a view a notice the user has no access to.
|
||||
throw new ClientException(_('Access restricted.'), 403);
|
||||
@@ -128,43 +133,20 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_single_json_status($this->notice);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->showSingleAtomStatus($this->notice);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Exception thrown requesting an unsupported notice output format.
|
||||
// TRANS: %s is the requested output format.
|
||||
throw new Exception(sprintf(_("Unsupported format: %s."), $this->format));
|
||||
}
|
||||
} 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
|
||||
);
|
||||
}
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_single_json_status($this->notice);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->showSingleAtomStatus($this->notice);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Exception thrown requesting an unsupported notice output format.
|
||||
// TRANS: %s is the requested output format.
|
||||
throw new Exception(sprintf(_("Unsupported format: %s."), $this->format));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,11 +170,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
return strtotime($this->notice->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
return strtotime($this->notice->created);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,20 +183,15 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->notice->id,
|
||||
strtotime($this->notice->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->notice->id,
|
||||
strtotime($this->notice->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
function deleteNotice()
|
||||
@@ -236,7 +209,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
var $in_reply_to_status_id = null;
|
||||
var $lat = null;
|
||||
var $lon = null;
|
||||
var $media_ids = array(); // file_id in the keys
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
@@ -167,6 +168,19 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
$this->status = $this->trimmed('status');
|
||||
$this->lat = $this->trimmed('lat');
|
||||
$this->lon = $this->trimmed('long');
|
||||
$matches = array();
|
||||
common_debug(get_called_class().': media_ids=='._ve($this->trimmed('media_ids')));
|
||||
if (preg_match_all('/\d+/', $this->trimmed('media_ids'), $matches) !== false) {
|
||||
foreach (array_unique($matches[0]) as $match) {
|
||||
try {
|
||||
$this->media_ids[$match] = File::getByID($match);
|
||||
} catch (EmptyIdException $e) {
|
||||
// got a zero from the client, at least Twidere does this on occasion
|
||||
} catch (NoResultException $e) {
|
||||
// File ID was not found. Do we abort and report to the client?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->in_reply_to_status_id
|
||||
= intval($this->trimmed('in_reply_to_status_id'));
|
||||
@@ -211,7 +225,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
$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
|
||||
|
||||
@@ -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;
|
||||
try {
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
$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) {
|
||||
// There was no uploaded media for us today.
|
||||
}
|
||||
|
||||
/* Do call shortenlinks here & check notice length since notice is about to be saved & sent */
|
||||
$status_shortened = $this->auth_user->shortenlinks($this->status);
|
||||
$status_shortened = $this->auth_user->shortenLinks($this->status);
|
||||
|
||||
if (Notice::contentTooLong($status_shortened)) {
|
||||
if ($upload instanceof MediaFile) {
|
||||
|
||||
@@ -51,19 +51,10 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
common_debug("apitimelinetag prepare()");
|
||||
|
||||
$this->tag = $this->arg('tag');
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
@@ -79,9 +70,9 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle($args);
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
@@ -172,21 +163,12 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
$notice = Notice_tag::getStream($this->tag)->getNotices(($this->page - 1) * $this->count,
|
||||
$this->count + 1,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
$notice = Notice_tag::getStream(
|
||||
$this->tag,
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count + 1,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
return $notice->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+35
-170
@@ -34,9 +34,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the authenticating
|
||||
@@ -79,6 +77,10 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
$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;
|
||||
@@ -111,11 +113,11 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
{
|
||||
// We'll use the shared params from the Atom stub
|
||||
// for other feed types.
|
||||
$atom = new AtomUserNoticeFeed($this->target->getUser(), $this->auth_user);
|
||||
$atom = new AtomUserNoticeFeed($this->target->getUser(), $this->scoped);
|
||||
|
||||
$link = common_local_url(
|
||||
'showstream',
|
||||
array('nickname' => $this->target->nickname)
|
||||
array('nickname' => $this->target->getNickname())
|
||||
);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
@@ -123,7 +125,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
// FriendFeed's SUP protocol
|
||||
// Also added RSS and Atom feeds
|
||||
|
||||
$suplink = common_local_url('sup', null, null, $this->target->id);
|
||||
$suplink = common_local_url('sup', null, null, $this->target->getID());
|
||||
header('X-SUP-ID: ' . $suplink);
|
||||
|
||||
|
||||
@@ -131,7 +133,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
$nextUrl = !empty($this->next_id)
|
||||
? common_local_url('ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->id),
|
||||
'id' => $this->target->getID()),
|
||||
array('max_id' => $this->next_id))
|
||||
: null;
|
||||
|
||||
@@ -143,11 +145,11 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
|
||||
$prevUrl = common_local_url('ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->id),
|
||||
'id' => $this->target->getID()),
|
||||
$prevExtra);
|
||||
$firstUrl = common_local_url('ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->id));
|
||||
'id' => $this->target->getID()));
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
@@ -202,7 +204,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc = new ActivityStreamJSONDocument($this->scoped);
|
||||
$doc->setTitle($atom->title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
@@ -303,9 +305,9 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_user_cache_hash($this->scoped),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
$this->target->getID(),
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
@@ -317,10 +319,10 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
if (empty($this->auth_user) ||
|
||||
$this->auth_user->id != $this->target->id) {
|
||||
if (!$this->scoped instanceof Profile ||
|
||||
!$this->target->sameAs($this->scoped)) {
|
||||
// TRANS: Client error displayed trying to add a notice to another user's timeline.
|
||||
$this->clientError(_('Only the user can add to their own timeline.'));
|
||||
$this->clientError(_('Only the user can add to their own timeline.'), 403);
|
||||
}
|
||||
|
||||
// Only handle posts for Atom
|
||||
@@ -352,165 +354,28 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
|
||||
$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))) {
|
||||
if ($activity->verb != ActivityVerb::POST) {
|
||||
// TRANS: Client error displayed when not using the POST verb. Do not translate POST.
|
||||
$this->clientError(_('Can only handle POST activities.'));
|
||||
}
|
||||
// Reset activity data so we can handle it in the same functions as with OStatus
|
||||
// because we don't let clients set their own UUIDs... Not sure what AtomPub thinks
|
||||
// about that though.
|
||||
$activity->id = null;
|
||||
$activity->actor = null; // not used anyway, we use $this->target
|
||||
$activity->objects[0]->id = null;
|
||||
|
||||
$note = $activity->objects[0];
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
$saved = $this->postNote($activity);
|
||||
|
||||
Event::handle('EndAtomPubNewActivity', array($activity, $this->target->getUser(), $saved));
|
||||
$stored = null;
|
||||
if (Event::handle('StartAtomPubNewActivity', array($activity, $this->target, &$stored))) {
|
||||
// TRANS: Client error displayed when not using the POST verb. Do not translate POST.
|
||||
throw new ClientException(_('Could not handle this Atom Activity.'));
|
||||
}
|
||||
|
||||
if (!empty($saved)) {
|
||||
header('HTTP/1.1 201 Created');
|
||||
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $saved->id,
|
||||
'format' => 'atom')));
|
||||
$this->showSingleAtomStatus($saved);
|
||||
if (!$stored instanceof Notice) {
|
||||
throw new ServerException('Server did not create a Notice object from handled AtomPub activity.');
|
||||
}
|
||||
}
|
||||
Event::handle('EndAtomPubNewActivity', array($activity, $this->target, $stored));
|
||||
|
||||
function postNote($activity)
|
||||
{
|
||||
$note = $activity->objects[0];
|
||||
|
||||
// Use summary as fallback for content
|
||||
|
||||
if (!empty($note->content)) {
|
||||
$sourceContent = $note->content;
|
||||
} else if (!empty($note->summary)) {
|
||||
$sourceContent = $note->summary;
|
||||
} else if (!empty($note->title)) {
|
||||
$sourceContent = $note->title;
|
||||
} else {
|
||||
// @fixme fetch from $sourceUrl?
|
||||
// TRANS: Client error displayed when posting a notice without content through the API.
|
||||
// TRANS: %d is the notice ID (number).
|
||||
$this->clientError(sprintf(_('No content for notice %d.'), $note->id));
|
||||
}
|
||||
|
||||
// Get (safe!) HTML and text versions of the content
|
||||
|
||||
$rendered = $this->purify($sourceContent);
|
||||
$content = common_strip_html($rendered);
|
||||
|
||||
$shortened = $this->auth_user->shortenLinks($content);
|
||||
|
||||
$options = array('is_local' => Notice::LOCAL_PUBLIC,
|
||||
'rendered' => $rendered,
|
||||
'replies' => array(),
|
||||
'groups' => array(),
|
||||
'tags' => array(),
|
||||
'urls' => array());
|
||||
|
||||
// accept remote URI (not necessarily a good idea)
|
||||
|
||||
common_debug("Note ID is {$note->id}");
|
||||
|
||||
if (!empty($note->id)) {
|
||||
$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 (!empty($activity->time)) {
|
||||
common_log(LOG_NOTICE, "Saving client-supplied create time {$activity->time}");
|
||||
$options['created'] = common_sql_date($activity->time);
|
||||
}
|
||||
|
||||
// Check for optional attributes...
|
||||
|
||||
if ($activity->context instanceof ActivityContext) {
|
||||
|
||||
foreach ($activity->context->attention as $uri=>$type) {
|
||||
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
|
||||
// @fixme what about conversation ID?
|
||||
|
||||
if (!empty($activity->context->replyToID)) {
|
||||
$orig = Notice::getKV('uri',
|
||||
$activity->context->replyToID);
|
||||
if (!empty($orig)) {
|
||||
$options['reply_to'] = $orig->id;
|
||||
}
|
||||
}
|
||||
|
||||
$location = $activity->context->location;
|
||||
|
||||
if ($location) {
|
||||
$options['lat'] = $location->lat;
|
||||
$options['lon'] = $location->lon;
|
||||
if ($location->location_id) {
|
||||
$options['location_ns'] = $location->location_ns;
|
||||
$options['location_id'] = $location->location_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atom categories <-> hashtags
|
||||
|
||||
foreach ($activity->categories as $cat) {
|
||||
if ($cat->term) {
|
||||
$term = common_canonical_tag($cat->term);
|
||||
if ($term) {
|
||||
$options['tags'][] = $term;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atom enclosures -> attachment URLs
|
||||
foreach ($activity->enclosures as $href) {
|
||||
// @fixme save these locally or....?
|
||||
$options['urls'][] = $href;
|
||||
}
|
||||
|
||||
$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);
|
||||
header('HTTP/1.1 201 Created');
|
||||
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $stored->getID(),
|
||||
'format' => 'atom')));
|
||||
$this->showSingleAtomStatus($stored);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,18 +230,11 @@ class AtompubsubscriptionfeedAction extends AtompubAction
|
||||
$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
|
||||
// TRANS: Client error displayed trying to subscribe to an already subscribed profile.
|
||||
// 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));
|
||||
$this->clientError($e->getMessage(), 409);
|
||||
}
|
||||
|
||||
Event::handle('EndAtomPubNewActivity', array($activity, $sub));
|
||||
|
||||
@@ -59,9 +59,9 @@ class Attachment_thumbnailAction extends AttachmentAction
|
||||
try {
|
||||
$thumbnail = $this->attachment->getThumbnail($this->thumb_w, $this->thumb_h, $this->thumb_c);
|
||||
} catch (UseFileAsThumbnailException $e) {
|
||||
common_redirect($e->file->getUrl());
|
||||
common_redirect($e->file->getUrl(), 302);
|
||||
}
|
||||
|
||||
common_redirect($thumbnail->getUrl());
|
||||
common_redirect(File_thumbnail::url($thumbnail->filename), 302);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
define('MAX_ORIGINAL', 480);
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Upload an avatar
|
||||
@@ -82,11 +76,11 @@ class AvatarsettingsAction extends SettingsAction
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
if ($this->mode == 'crop') {
|
||||
@@ -249,52 +243,19 @@ class AvatarsettingsAction extends SettingsAction
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a post
|
||||
*
|
||||
* We mux on the button name to figure out what the user actually wanted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
// 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 ($this->arg('upload')) {
|
||||
$this->uploadAvatar();
|
||||
} else if ($this->arg('crop')) {
|
||||
$this->cropAvatar();
|
||||
} else if ($this->arg('delete')) {
|
||||
$this->deleteAvatar();
|
||||
} else {
|
||||
// TRANS: Unexpected validation error on avatar upload form.
|
||||
$this->showForm(_('Unexpected form submission.'));
|
||||
}
|
||||
if ($this->trimmed('upload')) {
|
||||
return $this->uploadAvatar();
|
||||
} else if ($this->trimmed('crop')) {
|
||||
return $this->cropAvatar();
|
||||
} else if ($this->trimmed('delete')) {
|
||||
return $this->deleteAvatar();
|
||||
} else {
|
||||
// TRANS: Unexpected validation error on avatar upload form.
|
||||
throw new ClientException(_('Unexpected form submission.'));
|
||||
}
|
||||
Event::handle('EndAvatarSaveForm', array($this));
|
||||
}
|
||||
}
|
||||
@@ -309,21 +270,12 @@ class AvatarsettingsAction extends SettingsAction
|
||||
*/
|
||||
function uploadAvatar()
|
||||
{
|
||||
try {
|
||||
$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;
|
||||
}
|
||||
// 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');
|
||||
|
||||
$cur = common_current_user();
|
||||
$type = $imagefile->preferredType();
|
||||
$filename = Avatar::filename($cur->id,
|
||||
$filename = Avatar::filename($this->scoped->getID(),
|
||||
image_type_to_extension($type),
|
||||
null,
|
||||
'tmp'.common_timestamp());
|
||||
@@ -344,8 +296,7 @@ class AvatarsettingsAction extends SettingsAction
|
||||
$this->mode = 'crop';
|
||||
|
||||
// TRANS: Avatar upload form instruction after uploading a file.
|
||||
$this->showForm(_('Pick a square area of the image to be your avatar.'),
|
||||
true);
|
||||
return _('Pick a square area of the image to be your avatar.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -357,36 +308,46 @@ class AvatarsettingsAction extends SettingsAction
|
||||
{
|
||||
$filedata = $_SESSION['FILEDATA'];
|
||||
|
||||
if (!$filedata) {
|
||||
if (empty($filedata)) {
|
||||
// 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'])
|
||||
? $filedata['height'] : $filedata['width'];
|
||||
$file_d = min($filedata['width'], $filedata['height']);
|
||||
|
||||
$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_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;
|
||||
$size = intval(min($dest_w, $dest_h, MAX_ORIGINAL));
|
||||
$size = intval(min($dest_w, $dest_h, common_config('avatar', 'maxsize')));
|
||||
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
$box = array('width' => $size, 'height' => $size,
|
||||
'x' => $dest_x, 'y' => $dest_y,
|
||||
'w' => $dest_w, 'h' => $dest_h);
|
||||
|
||||
$imagefile = new ImageFile($user->id, $filedata['filepath']);
|
||||
$filename = $imagefile->resize($size, $dest_x, $dest_y, $dest_w, $dest_h);
|
||||
$imagefile = new ImageFile(null, $filedata['filepath']);
|
||||
$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']);
|
||||
unset($_SESSION['FILEDATA']);
|
||||
$this->mode = 'upload';
|
||||
// TRANS: Success message for having updated a user avatar.
|
||||
$this->showForm(_('Avatar updated.'), true);
|
||||
} 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.'));
|
||||
return _('Avatar updated.');
|
||||
}
|
||||
|
||||
// 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 +357,10 @@ class AvatarsettingsAction extends SettingsAction
|
||||
*/
|
||||
function deleteAvatar()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
|
||||
Avatar::deleteFromProfile($profile);
|
||||
Avatar::deleteFromProfile($this->scoped);
|
||||
|
||||
// TRANS: Success message for deleting a user avatar.
|
||||
$this->showForm(_('Avatar deleted.'), true);
|
||||
return _('Avatar deleted.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-172
@@ -28,11 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class BackupaccountAction extends Action
|
||||
class BackupaccountAction extends FormAction
|
||||
{
|
||||
/**
|
||||
* Returns the title of the page
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
protected $form = 'BackupAccount';
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Title for backup account page.
|
||||
return _('Backup account');
|
||||
}
|
||||
|
||||
/**
|
||||
* For initializing members of the class.
|
||||
*
|
||||
* @param array $argarray misc. arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function prepare($argarray)
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($argarray);
|
||||
|
||||
$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)) {
|
||||
if (!$this->scoped->hasRight(Right::BACKUPACCOUNT)) {
|
||||
// TRANS: Client exception thrown when trying to backup an account without having backup rights.
|
||||
throw new ClientException(_('You may not backup your account.'), 403);
|
||||
}
|
||||
@@ -87,40 +64,11 @@ class BackupaccountAction extends Action
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler method
|
||||
*
|
||||
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($argarray=null)
|
||||
protected function doPost()
|
||||
{
|
||||
parent::handle($argarray);
|
||||
$stream = new UserActivityStream($this->scoped->getUser(), true, UserActivityStream::OUTPUT_RAW);
|
||||
|
||||
if ($this->isPost()) {
|
||||
$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-Disposition: attachment; filename='.urlencode($this->scoped->getNickname()).'.atom');
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
// @fixme atom feed logic is in getString...
|
||||
@@ -128,39 +76,10 @@ class BackupaccountAction extends Action
|
||||
$this->raw($stream->getString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
public function isReadOnly($args) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last modified, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string last modified http header
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
// For comparison with If-Last-Modified
|
||||
@@ -168,89 +87,8 @@ class BackupaccountAction extends Action
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return etag, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string etag http header
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
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.'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,23 +43,17 @@ class CancelsubscriptionAction extends FormAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$profile_id = $this->int('unsubscribeto');
|
||||
$this->target = Profile::getKV('id', $profile_id);
|
||||
if (!$this->target instanceof Profile) {
|
||||
throw new NoProfileException($profile_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
parent::handlePost();
|
||||
|
||||
try {
|
||||
$request = Subscription_queue::pkeyGet(array('subscriber' => $this->scoped->id,
|
||||
'subscribed' => $this->target->id));
|
||||
@@ -70,7 +64,7 @@ class CancelsubscriptionAction extends FormAction
|
||||
common_debug('Tried to cancel a non-existing pending subscription');
|
||||
}
|
||||
|
||||
if (StatusNet::isAjax()) {
|
||||
if (GNUsocial::isAjax()) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title after unsubscribing from a group.
|
||||
@@ -82,10 +76,7 @@ class CancelsubscriptionAction extends FormAction
|
||||
$this->elementEnd('body');
|
||||
$this->endHTML();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,24 +49,9 @@ class ConversationAction extends ManagedAction
|
||||
var $page = null;
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if id not passed in
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
$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;
|
||||
$this->conv = Conversation::getByID($this->int('id'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,14 +75,14 @@ class ConversationAction extends ManagedAction
|
||||
function showContent()
|
||||
{
|
||||
if (Event::handle('StartShowConversation', array($this, $this->conv, $this->scoped))) {
|
||||
$notices = $this->conv->getNotices();
|
||||
$notices = $this->conv->getNotices($this->scoped);
|
||||
$nl = new FullThreadedNoticeList($notices, $this, $this->scoped);
|
||||
$cnt = $nl->show();
|
||||
}
|
||||
Event::handle('EndShowConversation', array($this, $this->conv, $this->scoped));
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -108,7 +93,7 @@ class ConversationAction extends ManagedAction
|
||||
return array(new Feed(Feed::JSON,
|
||||
common_local_url('apiconversation',
|
||||
array(
|
||||
'id' => $this->conv->id,
|
||||
'id' => $this->conv->getID(),
|
||||
'format' => 'as')),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
@@ -116,7 +101,7 @@ class ConversationAction extends ManagedAction
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('apiconversation',
|
||||
array(
|
||||
'id' => $this->conv->id,
|
||||
'id' => $this->conv->getID(),
|
||||
'format' => 'rss')),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
@@ -124,11 +109,11 @@ class ConversationAction extends ManagedAction
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('apiconversation',
|
||||
array(
|
||||
'id' => $this->conv->id,
|
||||
'id' => $this->conv->getID(),
|
||||
'format' => 'atom')),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
_('Conversation feed (Activity Streams JSON)')));
|
||||
_('Conversation feed (Atom)')));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-139
@@ -28,80 +28,24 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
// @todo FIXME: documentation needed.
|
||||
class DeletenoticeAction extends Action
|
||||
class DeletenoticeAction extends FormAction
|
||||
{
|
||||
var $error = null;
|
||||
var $user = null;
|
||||
var $notice = null;
|
||||
var $profile = null;
|
||||
var $user_profile = null;
|
||||
protected $notice = null;
|
||||
|
||||
function prepare($args)
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->notice = Notice::getByID($this->trimmed('notice'));
|
||||
|
||||
$this->user = common_current_user();
|
||||
|
||||
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)) {
|
||||
if (!$this->scoped->sameAs($this->notice->getProfile()) &&
|
||||
!$this->scoped->hasRight(Right::DELETEOTHERSNOTICE)) {
|
||||
// TRANS: Error message displayed trying to delete a notice that was not made by the current user.
|
||||
common_user_error(_('Cannot delete this notice.'));
|
||||
exit;
|
||||
$this->clientError(_('Cannot delete this notice.'));
|
||||
}
|
||||
// XXX: Ajax!
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->deleteNotice();
|
||||
} else if ($_SERVER['REQUEST_METHOD'] == 'GET') {
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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');
|
||||
$this->formOpts['notice'] = $this->notice;
|
||||
}
|
||||
|
||||
function getInstructions()
|
||||
@@ -117,84 +61,15 @@ class DeletenoticeAction extends Action
|
||||
return _('Delete notice');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for showing a page
|
||||
*
|
||||
* Stores an error and shows the page
|
||||
*
|
||||
* @param string $error Error, if any
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showForm($error = null)
|
||||
protected function doPost()
|
||||
{
|
||||
$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 (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) {
|
||||
$this->notice->delete();
|
||||
Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
|
||||
if (Event::handle('StartDeleteOwnNotice', array($this->scoped->getUser(), $this->notice))) {
|
||||
$this->notice->deleteAs($this->scoped);
|
||||
Event::handle('EndDeleteOwnNotice', array($this->scoped->getUser(), $this->notice));
|
||||
}
|
||||
}
|
||||
|
||||
$url = common_get_returnto();
|
||||
|
||||
if ($url) {
|
||||
common_set_returnto(null);
|
||||
} else {
|
||||
$url = common_local_url('public');
|
||||
}
|
||||
|
||||
common_redirect($url, 303);
|
||||
common_redirect(common_get_returnto(), 303);
|
||||
}
|
||||
}
|
||||
|
||||
+15
-20
@@ -27,9 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Delete a user
|
||||
@@ -44,33 +42,30 @@ class DeleteuserAction extends ProfileFormAction
|
||||
{
|
||||
var $user = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
function prepare(array $args=array())
|
||||
{
|
||||
if (!parent::prepare($args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
assert($this->scoped instanceof Profile);
|
||||
|
||||
assert(!empty($cur)); // checked by parent
|
||||
|
||||
if (!$cur->hasRight(Right::DELETEUSER)) {
|
||||
if (!$this->scoped->hasRight(Right::DELETEUSER)) {
|
||||
// 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);
|
||||
|
||||
if (empty($this->user)) {
|
||||
try {
|
||||
$this->user = $this->profile->getUser();
|
||||
} catch (NoSuchUserException $e) {
|
||||
// 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;
|
||||
|
||||
+15
-63
@@ -28,9 +28,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Documentation class.
|
||||
@@ -42,16 +40,14 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class DocAction extends Action
|
||||
class DocAction extends ManagedAction
|
||||
{
|
||||
var $output = null;
|
||||
var $filename = null;
|
||||
var $title = null;
|
||||
|
||||
function prepare($args)
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->title = $this->trimmed('title');
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]*$/', $this->title)) {
|
||||
$this->title = 'help';
|
||||
@@ -59,52 +55,11 @@ class DocAction extends Action
|
||||
$this->output = null;
|
||||
|
||||
$this->loadDoc();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function handle($args)
|
||||
public function title()
|
||||
{
|
||||
parent::handle($args);
|
||||
$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');
|
||||
return ucfirst($this->title);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,16 +74,9 @@ class DocAction extends Action
|
||||
$this->raw($this->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Page title.
|
||||
*
|
||||
* Uses the title of the document.
|
||||
*
|
||||
* @return page title
|
||||
*/
|
||||
function title()
|
||||
function showNoticeForm()
|
||||
{
|
||||
return ucfirst($this->title);
|
||||
// no notice form
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,11 +122,15 @@ class DocNav extends Menu
|
||||
{
|
||||
function show()
|
||||
{
|
||||
$stub = new HomeStubNav($this->action);
|
||||
$this->submenu(_m('MENU','Home'), $stub);
|
||||
if (Event::handle('StartDocNav', array($this))) {
|
||||
$stub = new HomeStubNav($this->action);
|
||||
$this->submenu(_m('MENU','Home'), $stub);
|
||||
|
||||
$docs = new DocListNav($this->action);
|
||||
$this->submenu(_m('MENU','Docs'), $docs);
|
||||
$docs = new DocListNav($this->action);
|
||||
$this->submenu(_m('MENU','Docs'), $docs);
|
||||
|
||||
Event::handle('EndDocNav', array($this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+70
-125
@@ -28,11 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Settings for email
|
||||
@@ -91,7 +87,7 @@ class EmailsettingsAction extends SettingsAction
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_email',
|
||||
@@ -112,8 +108,8 @@ class EmailsettingsAction extends SettingsAction
|
||||
// TRANS: Button label to remove a confirmed e-mail address.
|
||||
$this->submit('remove', _m('BUTTON','Remove'));
|
||||
} else {
|
||||
$confirm = $this->getConfirmation();
|
||||
if ($confirm) {
|
||||
try {
|
||||
$confirm = $this->getConfirmation();
|
||||
$this->element('p', array('id' => 'form_unconfirmed'), $confirm->address);
|
||||
$this->element('p', array('class' => 'form_note'),
|
||||
// TRANS: Form note in e-mail settings form.
|
||||
@@ -123,12 +119,12 @@ class EmailsettingsAction extends SettingsAction
|
||||
$this->hidden('email', $confirm->address);
|
||||
// TRANS: Button label to cancel an e-mail address confirmation procedure.
|
||||
$this->submit('cancel', _m('BUTTON','Cancel'));
|
||||
} else {
|
||||
} catch (NoResultException $e) {
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label for e-mail address input in e-mail settings form.
|
||||
$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: "example.org". It is one of the domain names reserved for
|
||||
// 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.'),
|
||||
$user->emailnotifynudge);
|
||||
$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));
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
@@ -254,56 +244,36 @@ class EmailsettingsAction extends SettingsAction
|
||||
*/
|
||||
function getConfirmation()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$confirm = new Confirm_address();
|
||||
|
||||
$confirm->user_id = $user->id;
|
||||
$confirm->user_id = $this->scoped->getID();
|
||||
$confirm->address_type = 'email';
|
||||
|
||||
if ($confirm->find(true)) {
|
||||
return $confirm;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new NoResultException($confirm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posts
|
||||
*
|
||||
* Since there are a lot of different options on the page, we
|
||||
* figure out what we're supposed to do based on which button was
|
||||
* pushed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
// 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->show_form(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
if ($this->arg('save')) {
|
||||
return $this->savePreferences();
|
||||
} else if ($this->arg('add')) {
|
||||
return $this->addAddress();
|
||||
} else if ($this->arg('cancel')) {
|
||||
return $this->cancelConfirmation();
|
||||
} 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.
|
||||
$this->showForm(_('Unexpected form submission.'));
|
||||
}
|
||||
// TRANS: Message given submitting a form with an unknown action in e-mail settings.
|
||||
throw new ClientException(_('Unexpected form submission.'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,44 +283,38 @@ class EmailsettingsAction extends SettingsAction
|
||||
*/
|
||||
function savePreferences()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) {
|
||||
$emailnotifysub = $this->boolean('emailnotifysub');
|
||||
$emailnotifymsg = $this->boolean('emailnotifymsg');
|
||||
$emailnotifynudge = $this->boolean('emailnotifynudge');
|
||||
$emailnotifyattn = $this->boolean('emailnotifyattn');
|
||||
$emailmicroid = $this->boolean('emailmicroid');
|
||||
$emailpost = $this->boolean('emailpost');
|
||||
|
||||
assert(!is_null($user)); // should already be checked
|
||||
$emailnotifysub = $this->booleanintstring('emailnotifysub');
|
||||
$emailnotifymsg = $this->booleanintstring('emailnotifymsg');
|
||||
$emailnotifynudge = $this->booleanintstring('emailnotifynudge');
|
||||
$emailnotifyattn = $this->booleanintstring('emailnotifyattn');
|
||||
$emailpost = $this->booleanintstring('emailpost');
|
||||
|
||||
$user = $this->scoped->getUser();
|
||||
$user->query('BEGIN');
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
$user->emailnotifysub = $emailnotifysub;
|
||||
$user->emailnotifymsg = $emailnotifymsg;
|
||||
$user->emailnotifynudge = $emailnotifynudge;
|
||||
$user->emailnotifyattn = $emailnotifyattn;
|
||||
$user->emailmicroid = $emailmicroid;
|
||||
$user->emailpost = $emailpost;
|
||||
|
||||
$result = $user->update($original);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
$user->query('ROLLBACK');
|
||||
// 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');
|
||||
|
||||
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()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$email = $this->trimmed('email');
|
||||
|
||||
// Some validation
|
||||
|
||||
if (!$email) {
|
||||
if (empty($email)) {
|
||||
// TRANS: Message given saving e-mail address without having provided one.
|
||||
$this->showForm(_('No email address.'));
|
||||
return;
|
||||
throw new ClientException(_('No email address.'));
|
||||
}
|
||||
|
||||
$email = common_canonical_email($email);
|
||||
|
||||
if (!$email) {
|
||||
if (empty($email)) {
|
||||
// TRANS: Message given saving e-mail address that cannot be normalised.
|
||||
$this->showForm(_('Cannot normalize that email address.'));
|
||||
return;
|
||||
throw new ClientException(_('Cannot normalize that email address.'));
|
||||
}
|
||||
if (!Validate::email($email, common_config('email', 'check_domain'))) {
|
||||
// TRANS: Message given saving e-mail address that not valid.
|
||||
$this->showForm(_('Not a valid email address.'));
|
||||
return;
|
||||
throw new ClientException(_('Not a valid email address.'));
|
||||
} else if ($user->email == $email) {
|
||||
// TRANS: Message given saving e-mail address that is already set.
|
||||
$this->showForm(_('That is already your email address.'));
|
||||
return;
|
||||
throw new ClientException(_('That is already your email address.'));
|
||||
} else if ($this->emailExists($email)) {
|
||||
// TRANS: Message given saving e-mail address that is already set for another user.
|
||||
$this->showForm(_('That email address already belongs '.
|
||||
'to another user.'));
|
||||
return;
|
||||
throw new ClientException(_('That email address already belongs to another user.'));
|
||||
}
|
||||
|
||||
if (Event::handle('StartAddEmailAddress', array($user, $email))) {
|
||||
@@ -400,7 +358,7 @@ class EmailsettingsAction extends SettingsAction
|
||||
|
||||
$confirm->address = $email;
|
||||
$confirm->address_type = 'email';
|
||||
$confirm->user_id = $user->id;
|
||||
$confirm->user_id = $user->getID();
|
||||
$confirm->code = common_confirmation_code(64);
|
||||
|
||||
$result = $confirm->insert();
|
||||
@@ -408,20 +366,19 @@ class EmailsettingsAction extends SettingsAction
|
||||
if ($result === false) {
|
||||
common_log_db_error($confirm, 'INSERT', __FILE__);
|
||||
// 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);
|
||||
common_debug('Sending confirmation address for user '.$user->getID().' to email '.$email);
|
||||
mail_confirm_address($user, $confirm->code, $user->getNickname(), $email);
|
||||
|
||||
Event::handle('EndAddEmailAddress', array($user, $email));
|
||||
}
|
||||
|
||||
// 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 '.
|
||||
'on how to use it.');
|
||||
|
||||
$this->showForm($msg, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,31 +388,29 @@ class EmailsettingsAction extends SettingsAction
|
||||
*/
|
||||
function cancelConfirmation()
|
||||
{
|
||||
$email = $this->arg('email');
|
||||
$email = $this->trimmed('email');
|
||||
|
||||
$confirm = $this->getConfirmation();
|
||||
|
||||
if (!$confirm) {
|
||||
try {
|
||||
$confirm = $this->getConfirmation();
|
||||
if ($confirm->address !== $email) {
|
||||
// TRANS: Message given canceling e-mail address confirmation for the wrong e-mail address.
|
||||
throw new ClientException(_('That is the wrong email address.'));
|
||||
}
|
||||
} catch (NoResultException $e) {
|
||||
// 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.
|
||||
$this->showForm(_('That is the wrong email address.'));
|
||||
return;
|
||||
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
||||
}
|
||||
|
||||
$result = $confirm->delete();
|
||||
|
||||
if (!$result) {
|
||||
if ($result === false) {
|
||||
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.'));
|
||||
throw new ServerException(_('Could not delete email confirmation.'));
|
||||
}
|
||||
|
||||
// TRANS: Message given after successfully canceling e-mail address confirmation.
|
||||
$this->showForm(_('Email confirmation cancelled.'), true);
|
||||
return _('Email confirmation cancelled.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -467,26 +422,22 @@ class EmailsettingsAction extends SettingsAction
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$email = $this->arg('email');
|
||||
$email = $this->trimmed('email');
|
||||
|
||||
// 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: registered for the active user.
|
||||
$this->showForm(_('That is not your email address.'));
|
||||
return;
|
||||
throw new ClientException(_('That is not your email address.'));
|
||||
}
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
$user->email = null;
|
||||
|
||||
// Throws exception on failure. Also performs it within a transaction.
|
||||
$user->updateWithKeys($original);
|
||||
|
||||
// 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 +449,19 @@ class EmailsettingsAction extends SettingsAction
|
||||
{
|
||||
$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.
|
||||
$this->showForm(_('No incoming email address.'));
|
||||
return;
|
||||
throw new AlreadyFulfilledException(_('No incoming email address.'));
|
||||
}
|
||||
|
||||
$orig = clone($user);
|
||||
|
||||
$user->incomingemail = null;
|
||||
$user->emailpost = 0;
|
||||
|
||||
// Throws exception on failure. Also performs it within a transaction.
|
||||
$user->updateWithKeys($orig);
|
||||
|
||||
// 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 +472,14 @@ class EmailsettingsAction extends SettingsAction
|
||||
function newIncoming()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$orig = clone($user);
|
||||
|
||||
$user->incomingemail = mail_new_incoming_address();
|
||||
$user->emailpost = 1;
|
||||
|
||||
// Throws exception on failure. Also performs it within a transaction.
|
||||
$user->updateWithKeys($orig);
|
||||
|
||||
// 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 +498,10 @@ class EmailsettingsAction extends SettingsAction
|
||||
|
||||
$other = User::getKV('email', $email);
|
||||
|
||||
if (!$other) {
|
||||
if (!$other instanceof User) {
|
||||
return false;
|
||||
} else {
|
||||
return $other->id != $user->id;
|
||||
}
|
||||
|
||||
return $other->id != $user->id;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-9
@@ -17,24 +17,22 @@
|
||||
* 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('LISTENEE', -1);
|
||||
define('BOTH', 0);
|
||||
|
||||
// @todo XXX: Documentation missing.
|
||||
class FoafAction extends Action
|
||||
class FoafAction extends ManagedAction
|
||||
{
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$nickname_arg = $this->arg('nickname');
|
||||
|
||||
if (empty($nickname_arg)) {
|
||||
@@ -69,10 +67,8 @@ class FoafAction extends Action
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
public function showPage()
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
header('Content-Type: application/rdf+xml');
|
||||
|
||||
$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?)
|
||||
$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));
|
||||
}
|
||||
if ($this->profile->fullname) {
|
||||
|
||||
+6
-42
@@ -28,12 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Permalink for a group
|
||||
@@ -47,53 +42,22 @@ 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
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class GroupbyidAction extends Action
|
||||
class GroupbyidAction extends ManagedAction
|
||||
{
|
||||
/** group we're viewing. */
|
||||
var $group = null;
|
||||
protected $group = null;
|
||||
|
||||
/**
|
||||
* Is this page read-only?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->arg('id');
|
||||
|
||||
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;
|
||||
$this->group = User_group::getByID($this->arg('id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Shows a profile for the group, some controls, and a list of
|
||||
* group notices.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
public function showPage()
|
||||
{
|
||||
common_redirect($this->group->homeUrl(), 303);
|
||||
}
|
||||
|
||||
+13
-12
@@ -28,13 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
define('MAX_ORIGINAL', 480);
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Upload an avatar
|
||||
@@ -390,13 +384,20 @@ class GrouplogoAction extends GroupAction
|
||||
$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_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$filedata['height'];
|
||||
$size = min($dest_w, $dest_h);
|
||||
$size = ($size > MAX_ORIGINAL) ? MAX_ORIGINAL:$size;
|
||||
$size = min($dest_w, $dest_h, common_config('avatar', 'maxsize'));
|
||||
$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']);
|
||||
$filename = $imagefile->resize($size, $dest_x, $dest_y, $dest_w, $dest_h);
|
||||
$profile = $this->group->getProfile();
|
||||
|
||||
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']);
|
||||
unset($_SESSION['FILEDATA']);
|
||||
$this->mode = 'upload';
|
||||
|
||||
+14
-48
@@ -28,11 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
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
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class groupRssAction extends Rss10Action
|
||||
class GroupRssAction extends TargetedRss10Action
|
||||
{
|
||||
/** group we're viewing. */
|
||||
var $group = null;
|
||||
protected $group = null;
|
||||
|
||||
/**
|
||||
* Is this page read-only?
|
||||
@@ -60,18 +56,8 @@ class groupRssAction extends Rss10Action
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the action
|
||||
*
|
||||
* Reads and validates arguments and instantiates the attributes.
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
protected function doStreamPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$nickname_arg = $this->arg('nickname');
|
||||
$nickname = common_canonical_nickname($nickname_arg);
|
||||
@@ -90,52 +76,32 @@ class groupRssAction extends Rss10Action
|
||||
|
||||
$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.
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
}
|
||||
|
||||
$this->group = User_group::getKV('id', $local->group_id);
|
||||
|
||||
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);
|
||||
return true;
|
||||
$this->group = $local->getGroup();
|
||||
$this->target = $this->group->getProfile();
|
||||
}
|
||||
|
||||
function getNotices($limit=0)
|
||||
protected function getNotices()
|
||||
{
|
||||
$group = $this->group;
|
||||
|
||||
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;
|
||||
$stream = $this->group->getNotices(0, $this->limit);
|
||||
return $stream->fetchAll();
|
||||
}
|
||||
|
||||
function getChannel()
|
||||
{
|
||||
$group = $this->group;
|
||||
$c = array('url' => common_local_url('grouprss',
|
||||
array('nickname' =>
|
||||
$group->nickname)),
|
||||
$this->target->getNickname())),
|
||||
// TRANS: Message is used as link title. %s is a user nickname.
|
||||
'title' => sprintf(_('%s timeline'), $group->nickname),
|
||||
'link' => common_local_url('showgroup', array('nickname' => $group->nickname)),
|
||||
'title' => sprintf(_('%s timeline'), $this->target->getNickname()),
|
||||
'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.
|
||||
'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;
|
||||
}
|
||||
|
||||
|
||||
+51
-99
@@ -27,9 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Settings for Jabber/XMPP integration
|
||||
@@ -118,8 +116,8 @@ class ImsettingsAction extends SettingsAction
|
||||
// TRANS: Button label to remove a confirmed IM address.
|
||||
$this->submit('remove', _m('BUTTON','Remove'));
|
||||
} else {
|
||||
$confirm = $this->getConfirmation($transport);
|
||||
if ($confirm) {
|
||||
try {
|
||||
$confirm = $this->getConfirmation($transport);
|
||||
$this->element('p', 'form_unconfirmed', $confirm->address);
|
||||
// TRANS: Form note in IM settings form.
|
||||
$this->element('p', 'form_note',
|
||||
@@ -134,7 +132,7 @@ class ImsettingsAction extends SettingsAction
|
||||
$this->hidden('screenname', $confirm->address);
|
||||
// TRANS: Button label to cancel an IM address confirmation procedure.
|
||||
$this->submit('cancel', _m('BUTTON','Cancel'));
|
||||
} else {
|
||||
} catch (NoResultException $e) {
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label for IM address.
|
||||
@@ -179,8 +177,6 @@ class ImsettingsAction extends SettingsAction
|
||||
// TRANS: Checkbox label in IM preferences form.
|
||||
array('name'=>'replies', 'description'=>_('Send me replies '.
|
||||
'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)
|
||||
{
|
||||
@@ -211,57 +207,35 @@ class ImsettingsAction extends SettingsAction
|
||||
*/
|
||||
function getConfirmation($transport)
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$confirm = new Confirm_address();
|
||||
|
||||
$confirm->user_id = $user->id;
|
||||
$confirm->user_id = $this->scoped->getID();
|
||||
$confirm->address_type = $transport;
|
||||
|
||||
if ($confirm->find(true)) {
|
||||
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
|
||||
* to do the actual task requested.
|
||||
*
|
||||
* All sub-functions reload the form with a message -- success or failure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
// 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')) {
|
||||
$this->savePreferences();
|
||||
return $this->savePreferences();
|
||||
} else if ($this->arg('add')) {
|
||||
$this->addAddress();
|
||||
return $this->addAddress();
|
||||
} else if ($this->arg('cancel')) {
|
||||
$this->cancelConfirmation();
|
||||
return $this->cancelConfirmation();
|
||||
} else if ($this->arg('remove')) {
|
||||
$this->removeAddress();
|
||||
} else {
|
||||
// TRANS: Message given submitting a form with an unknown action in Instant Messaging settings.
|
||||
$this->showForm(_('Unexpected form submission.'));
|
||||
return $this->removeAddress();
|
||||
}
|
||||
// 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
|
||||
* set different settings
|
||||
@@ -270,14 +244,12 @@ class ImsettingsAction extends SettingsAction
|
||||
*/
|
||||
function savePreferences()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$user_im_prefs = new User_im_prefs();
|
||||
$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())
|
||||
{
|
||||
$preferences = array('notify', 'updatefrompresence', 'replies', 'microid');
|
||||
$preferences = array('notify', 'updatefrompresence', 'replies');
|
||||
do
|
||||
{
|
||||
$original = clone($user_im_prefs);
|
||||
@@ -289,15 +261,15 @@ class ImsettingsAction extends SettingsAction
|
||||
$result = $new->update($original);
|
||||
|
||||
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.
|
||||
$this->serverError(_('Could not update IM preferences.'));
|
||||
throw new ServerException(_('Could not update IM preferences.'));
|
||||
}
|
||||
}while($user_im_prefs->fetch());
|
||||
}
|
||||
$user_im_prefs->query('COMMIT');
|
||||
// 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()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$screenname = $this->trimmed('screenname');
|
||||
$transport = $this->trimmed('transport');
|
||||
|
||||
// Some validation
|
||||
|
||||
if (!$screenname) {
|
||||
if (empty($screenname)) {
|
||||
// TRANS: Message given saving IM address without having provided one.
|
||||
$this->showForm(_('No screenname.'));
|
||||
return;
|
||||
throw new ClientException(_('No screenname.'));
|
||||
}
|
||||
|
||||
if (!$transport) {
|
||||
if (empty($transport)) {
|
||||
// TRANS: Form validation error when no transport is available setting an IM address.
|
||||
$this->showForm(_('No transport.'));
|
||||
return;
|
||||
throw new ClientException(_('No transport.'));
|
||||
}
|
||||
|
||||
Event::handle('NormalizeImScreenname', array($transport, &$screenname));
|
||||
|
||||
if (!$screenname) {
|
||||
if (empty($screenname)) {
|
||||
// TRANS: Message given saving IM address that cannot be normalised.
|
||||
$this->showForm(_('Cannot normalize that screenname.'));
|
||||
return;
|
||||
throw new ClientException(_('Cannot normalize that screenname.'));
|
||||
}
|
||||
$valid = false;
|
||||
Event::handle('ValidateImScreenname', array($transport, $screenname, &$valid));
|
||||
if (!$valid) {
|
||||
// TRANS: Message given saving IM address that not valid.
|
||||
$this->showForm(_('Not a valid screenname.'));
|
||||
return;
|
||||
throw new ClientException(_('Not a valid screenname.'));
|
||||
} else if ($this->screennameExists($transport, $screenname)) {
|
||||
// TRANS: Message given saving IM address that is already set for another user.
|
||||
$this->showForm(_('Screenname already belongs to another user.'));
|
||||
return;
|
||||
throw new ClientException(_('Screenname already belongs to another user.'));
|
||||
}
|
||||
|
||||
$confirm = new Confirm_address();
|
||||
|
||||
$confirm->address = $screenname;
|
||||
$confirm->address_type = $transport;
|
||||
$confirm->user_id = $user->id;
|
||||
$confirm->user_id = $this->scoped->getID();
|
||||
$confirm->code = common_confirmation_code(64);
|
||||
$confirm->sent = common_sql_now();
|
||||
$confirm->claimed = common_sql_now();
|
||||
@@ -365,13 +330,10 @@ class ImsettingsAction extends SettingsAction
|
||||
$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.
|
||||
$msg = _('A confirmation code was sent '.
|
||||
'to the IM address you added.');
|
||||
|
||||
$this->showForm($msg, true);
|
||||
return _('A confirmation code was sent to the IM address you added.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -386,29 +348,27 @@ class ImsettingsAction extends SettingsAction
|
||||
$screenname = $this->trimmed('screenname');
|
||||
$transport = $this->trimmed('transport');
|
||||
|
||||
$confirm = $this->getConfirmation($transport);
|
||||
|
||||
if (!$confirm) {
|
||||
try {
|
||||
$confirm = $this->getConfirmation($transport);
|
||||
if ($confirm->address != $screenname) {
|
||||
// TRANS: Message given canceling IM address confirmation for the wrong IM address.
|
||||
throw new ClientException(_('That is the wrong IM address.'));
|
||||
}
|
||||
} catch (NoResultException $e) {
|
||||
// TRANS: Message given canceling Instant Messaging address confirmation that is not pending.
|
||||
$this->showForm(_('No pending confirmation to cancel.'));
|
||||
return;
|
||||
}
|
||||
if ($confirm->address != $screenname) {
|
||||
// TRANS: Message given canceling IM address confirmation for the wrong IM address.
|
||||
$this->showForm(_('That is the wrong IM address.'));
|
||||
return;
|
||||
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
||||
}
|
||||
|
||||
$result = $confirm->delete();
|
||||
|
||||
if (!$result) {
|
||||
if ($result === false) {
|
||||
common_log_db_error($confirm, 'DELETE', __FILE__);
|
||||
// TRANS: Server error thrown on database error canceling IM address confirmation.
|
||||
$this->serverError(_('Could not delete confirmation.'));
|
||||
throw new ServerException(_('Could not delete confirmation.'));
|
||||
}
|
||||
|
||||
// TRANS: Message given after successfully canceling IM address confirmation.
|
||||
$this->showForm(_('IM confirmation cancelled.'), true);
|
||||
return _('IM confirmation cancelled.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,34 +380,32 @@ class ImsettingsAction extends SettingsAction
|
||||
*/
|
||||
function removeAddress()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$screenname = $this->trimmed('screenname');
|
||||
$transport = $this->trimmed('transport');
|
||||
|
||||
// Maybe an old tab open...?
|
||||
|
||||
$user_im_prefs = new User_im_prefs();
|
||||
$user_im_prefs->user_id = $user->id;
|
||||
if(! ($user_im_prefs->find() && $user_im_prefs->fetch())) {
|
||||
$user_im_prefs->user_id = $this->scoped->getID();
|
||||
$user_im_prefs->transport = $transport;
|
||||
if (!$user_im_prefs->find(true)) {
|
||||
// TRANS: Message given trying to remove an IM address that is not
|
||||
// TRANS: registered for the active user.
|
||||
$this->showForm(_('That is not your screenname.'));
|
||||
return;
|
||||
throw new AlreadyFulfilledException(_('There were no preferences stored for this transport.'));
|
||||
}
|
||||
|
||||
$result = $user_im_prefs->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
if ($result === false) {
|
||||
common_log_db_error($user_im_prefs, 'UPDATE', __FILE__);
|
||||
// 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
|
||||
|
||||
// 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 +421,9 @@ class ImsettingsAction extends SettingsAction
|
||||
|
||||
function screennameExists($transport, $screenname)
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$user_im_prefs = new User_im_prefs();
|
||||
$user_im_prefs->transport = $transport;
|
||||
$user_im_prefs->screenname = $screenname;
|
||||
if($user_im_prefs->find() && $user_im_prefs->fetch()){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
return $user_im_prefs->find(true) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class InviteAction extends Action
|
||||
$this->already[] = $other;
|
||||
} else {
|
||||
try {
|
||||
Subscription::start($profile, $other);
|
||||
Subscription::ensureStart($profile, $other);
|
||||
$this->subbed[] = $other;
|
||||
} catch (Exception $e) {
|
||||
// subscription failed, but keep working
|
||||
|
||||
+2
-38
@@ -36,24 +36,6 @@ class LoginAction extends FormAction
|
||||
{
|
||||
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
|
||||
*
|
||||
@@ -79,10 +61,8 @@ class LoginAction extends FormAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
parent::handlePost();
|
||||
|
||||
// XXX: login throttle
|
||||
|
||||
$nickname = $this->trimmed('nickname');
|
||||
@@ -122,22 +102,6 @@ class LoginAction extends FormAction
|
||||
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()
|
||||
{
|
||||
parent::showScripts();
|
||||
@@ -208,7 +172,7 @@ class LoginAction extends FormAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function getInstructions()
|
||||
protected function getInstructions()
|
||||
{
|
||||
if (common_logged_in() && !common_is_real_login() &&
|
||||
common_get_returnto()) {
|
||||
|
||||
@@ -63,7 +63,7 @@ class LogoutAction extends ManagedAction
|
||||
}
|
||||
Event::handle('EndLogout', array($this));
|
||||
|
||||
common_redirect(common_local_url('startpage'));
|
||||
common_redirect(common_local_url('top'));
|
||||
}
|
||||
|
||||
// Accessed through the action on events
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class NetworkpublicAction extends PublicAction
|
||||
class NetworkpublicAction extends SitestreamAction
|
||||
{
|
||||
protected function streamPrepare()
|
||||
{
|
||||
@@ -28,13 +28,6 @@ class NetworkpublicAction extends PublicAction
|
||||
}
|
||||
}
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
// the PublicAction has some XRDS stuff that might be unique to the non-network public feed
|
||||
// FIXME: Solve this with a call that doesn't rely on parent:: and is unique for each class.
|
||||
ManagedAction::extraHead();
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
// Show invite button, as long as site isn't closed, and
|
||||
|
||||
@@ -28,9 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Add a new application
|
||||
@@ -43,7 +41,7 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class NewApplicationAction extends FormAction
|
||||
class NewApplicationAction extends SettingsAction
|
||||
{
|
||||
function title()
|
||||
{
|
||||
@@ -51,13 +49,12 @@ class NewApplicationAction extends FormAction
|
||||
return _('New application');
|
||||
}
|
||||
|
||||
protected function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
parent::handlePost();
|
||||
|
||||
if ($this->arg('cancel')) {
|
||||
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||
} elseif ($this->arg('save')) {
|
||||
//trySave will never return, just throw exception or redirect
|
||||
$this->trySave();
|
||||
}
|
||||
|
||||
@@ -65,30 +62,18 @@ class NewApplicationAction extends FormAction
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
}
|
||||
|
||||
function showForm($msg=null)
|
||||
protected function getForm()
|
||||
{
|
||||
$this->msg = $msg;
|
||||
$this->showPage();
|
||||
return new ApplicationEditForm($this);
|
||||
}
|
||||
|
||||
function showContent()
|
||||
protected function getInstructions()
|
||||
{
|
||||
$form = new ApplicationEditForm($this);
|
||||
$form->show();
|
||||
// TRANS: Form instructions for registering a new application.
|
||||
return _('Use this form to register a new application.');
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if ($this->msg) {
|
||||
$this->element('p', 'error', $this->msg);
|
||||
} else {
|
||||
$this->element('p', 'instructions',
|
||||
// TRANS: Form instructions for registering a new application.
|
||||
_('Use this form to register a new application.'));
|
||||
}
|
||||
}
|
||||
|
||||
private function trySave()
|
||||
protected function trySave()
|
||||
{
|
||||
$name = $this->trimmed('name');
|
||||
$description = $this->trimmed('description');
|
||||
@@ -153,7 +138,7 @@ class NewApplicationAction extends FormAction
|
||||
$app->query('BEGIN');
|
||||
|
||||
$app->name = $name;
|
||||
$app->owner = $this->scoped->id;
|
||||
$app->owner = $this->scoped->getID();
|
||||
$app->description = $description;
|
||||
$app->source_url = $source_url;
|
||||
$app->organization = $organization;
|
||||
@@ -181,6 +166,7 @@ class NewApplicationAction extends FormAction
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($consumer, 'INSERT', __FILE__);
|
||||
$app->query('ROLLBACK');
|
||||
// TRANS: Server error displayed when an application could not be registered in the database through the "New application" form.
|
||||
$this->serverError(_('Could not create application.'));
|
||||
}
|
||||
@@ -191,9 +177,9 @@ class NewApplicationAction extends FormAction
|
||||
|
||||
if (!$this->app_id) {
|
||||
common_log_db_error($app, 'INSERT', __FILE__);
|
||||
$app->query('ROLLBACK');
|
||||
// TRANS: Server error displayed when an application could not be registered in the database through the "New application" form.
|
||||
$this->serverError(_('Could not create application.'));
|
||||
$app->query('ROLLBACK');
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
+8
-25
@@ -29,9 +29,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Add a new group
|
||||
@@ -48,6 +46,8 @@ class NewgroupAction extends FormAction
|
||||
{
|
||||
protected $group;
|
||||
|
||||
protected $form = 'GroupEdit';
|
||||
|
||||
function getGroup() {
|
||||
return $this->group;
|
||||
}
|
||||
@@ -58,39 +58,23 @@ class NewgroupAction extends FormAction
|
||||
return _('New group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// $this->scoped is the current user profile
|
||||
if (!$this->scoped->hasRight(Right::CREATEGROUP)) {
|
||||
// TRANS: Client exception thrown when a user tries to create a group while banned.
|
||||
$this->clientError(_('You are not allowed to create groups on this site.'), 403);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function showContent()
|
||||
protected function getInstructions()
|
||||
{
|
||||
$form = new GroupEditForm($this);
|
||||
$form->show();
|
||||
// TRANS: Form instructions for group create form.
|
||||
return _('Use this form to create a new group.');
|
||||
}
|
||||
|
||||
public function showInstructions()
|
||||
protected function doPost()
|
||||
{
|
||||
$this->element('p', 'instructions',
|
||||
// TRANS: Form instructions for group create form.
|
||||
_('Use this form to create a new group.'));
|
||||
}
|
||||
|
||||
protected function handlePost()
|
||||
{
|
||||
parent::handlePost();
|
||||
|
||||
if (Event::handle('StartGroupSaveForm', array($this))) {
|
||||
$nickname = Nickname::normalize($this->trimmed('newnickname'), true);
|
||||
|
||||
@@ -133,7 +117,6 @@ class NewgroupAction extends FormAction
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($private) {
|
||||
|
||||
+71
-55
@@ -30,9 +30,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Action for posting new notices
|
||||
@@ -62,6 +60,9 @@ class NewnoticeAction extends FormAction
|
||||
// TRANS: Page title after sending a notice.
|
||||
return _('Notice posted');
|
||||
}
|
||||
if ($this->int('inreplyto')) {
|
||||
return _m('TITLE', 'New reply');
|
||||
}
|
||||
// TRANS: Page title for sending a new notice.
|
||||
return _m('TITLE','New notice');
|
||||
}
|
||||
@@ -80,7 +81,7 @@ class NewnoticeAction extends FormAction
|
||||
}
|
||||
|
||||
/**
|
||||
* This handlePost saves a new notice, based on arguments
|
||||
* This doPost saves a new notice, based on arguments
|
||||
*
|
||||
* If successful, will show the notice, or return an Ajax-y result.
|
||||
* If not, it will show an error message -- possibly Ajax-y.
|
||||
@@ -90,19 +91,32 @@ class NewnoticeAction extends FormAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
parent::handlePost();
|
||||
|
||||
assert($this->scoped); // XXX: maybe an error instead...
|
||||
assert($this->scoped instanceof Profile); // XXX: maybe an error instead...
|
||||
$user = $this->scoped->getUser();
|
||||
$content = $this->trimmed('status_textarea');
|
||||
$options = array();
|
||||
$content = $this->formOpts['content'];
|
||||
$options = array('source' => 'web');
|
||||
Event::handle('StartSaveNewNoticeWeb', array($this, $user, &$content, &$options));
|
||||
|
||||
if (!$content) {
|
||||
// TRANS: Client error displayed trying to send a notice without content.
|
||||
$this->clientError(_('No content!'));
|
||||
$upload = null;
|
||||
try {
|
||||
// throws exception on failure
|
||||
$upload = MediaFile::fromUpload('attach', $this->scoped);
|
||||
if (Event::handle('StartSaveNewNoticeAppendAttachment', array($this, $upload, &$content, &$options))) {
|
||||
$content .= ($content==='' ? '' : ' ') . $upload->shortUrl();
|
||||
}
|
||||
Event::handle('EndSaveNewNoticeAppendAttachment', array($this, $upload, &$content, &$options));
|
||||
|
||||
// We could check content length here if the URL was added, but I'll just let it slide for now...
|
||||
|
||||
$act->enclosures[] = $upload->getEnclosure();
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
// simply no attached media to the new notice
|
||||
if (empty($content)) {
|
||||
// TRANS: Client error displayed trying to send a notice without content.
|
||||
$this->clientError(_('No content!'));
|
||||
}
|
||||
}
|
||||
|
||||
$inter = new CommandInterpreter();
|
||||
@@ -110,7 +124,7 @@ class NewnoticeAction extends FormAction
|
||||
$cmd = $inter->handle_command($user, $content);
|
||||
|
||||
if ($cmd) {
|
||||
if (StatusNet::isAjax()) {
|
||||
if (GNUsocial::isAjax()) {
|
||||
$cmd->execute(new AjaxWebChannel($this));
|
||||
} else {
|
||||
$cmd->execute(new WebChannel($this));
|
||||
@@ -118,44 +132,36 @@ class NewnoticeAction extends FormAction
|
||||
return;
|
||||
}
|
||||
|
||||
$content_shortened = $user->shortenLinks($content);
|
||||
if (Notice::contentTooLong($content_shortened)) {
|
||||
if ($this->int('inreplyto')) {
|
||||
// Throws exception if the inreplyto Notice is given but not found.
|
||||
$parent = Notice::getByID($this->int('inreplyto'));
|
||||
} else {
|
||||
$parent = null;
|
||||
}
|
||||
|
||||
$act = new Activity();
|
||||
$act->verb = ActivityVerb::POST;
|
||||
$act->time = time();
|
||||
$act->actor = $this->scoped->asActivityObject();
|
||||
|
||||
// Reject notice if it is too long (without the HTML)
|
||||
// This is done after MediaFile::fromUpload etc. just to act the same as the ApiStatusesUpdateAction
|
||||
if (Notice::contentTooLong($content)) {
|
||||
// TRANS: Client error displayed when the parameter "status" is missing.
|
||||
// TRANS: %d is the maximum number of character for a notice.
|
||||
$this->clientError(sprintf(_m('That\'s too long. Maximum notice size is %d character.',
|
||||
'That\'s too long. Maximum notice size is %d characters.',
|
||||
Notice::maxContent()),
|
||||
Notice::maxContent()));
|
||||
throw new ClientException(sprintf(_m('That\'s too long. Maximum notice size is %d character.',
|
||||
'That\'s too long. Maximum notice size is %d characters.',
|
||||
Notice::maxContent()),
|
||||
Notice::maxContent()));
|
||||
}
|
||||
|
||||
$replyto = intval($this->trimmed('inreplyto'));
|
||||
if ($replyto) {
|
||||
$options['reply_to'] = $replyto;
|
||||
$act->context = new ActivityContext();
|
||||
|
||||
if ($parent instanceof Notice) {
|
||||
$act->context->replyToID = $parent->getUri();
|
||||
$act->context->replyToUrl = $parent->getUrl(true); // maybe we don't have to send true here to force a URL?
|
||||
}
|
||||
|
||||
$upload = null;
|
||||
try {
|
||||
// throws exception on failure
|
||||
$upload = MediaFile::fromUpload('attach', $this->scoped);
|
||||
if (Event::handle('StartSaveNewNoticeAppendAttachment', array($this, $upload, &$content_shortened, &$options))) {
|
||||
$content_shortened .= ' ' . $upload->shortUrl();
|
||||
}
|
||||
Event::handle('EndSaveNewNoticeAppendAttachment', array($this, $upload, &$content_shortened, &$options));
|
||||
|
||||
if (Notice::contentTooLong($content_shortened)) {
|
||||
$upload->delete();
|
||||
// TRANS: Client error displayed exceeding the maximum notice length.
|
||||
// TRANS: %d is the maximum length for a notice.
|
||||
$this->clientError(sprintf(_m('Maximum notice size is %d character, including attachment URL.',
|
||||
'Maximum notice size is %d characters, including attachment URL.',
|
||||
Notice::maxContent()),
|
||||
Notice::maxContent()));
|
||||
}
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
// simply no attached media to the new notice
|
||||
}
|
||||
|
||||
|
||||
if ($this->scoped->shareLocation()) {
|
||||
// use browser data if checked; otherwise profile data
|
||||
if ($this->arg('notice_data-geo')) {
|
||||
@@ -172,19 +178,29 @@ class NewnoticeAction extends FormAction
|
||||
$this->scoped);
|
||||
}
|
||||
|
||||
$options = array_merge($options, $locOptions);
|
||||
$act->context->location = Location::fromOptions($locOptions);
|
||||
}
|
||||
|
||||
$author_id = $this->scoped->id;
|
||||
$text = $content_shortened;
|
||||
$content = $this->scoped->shortenLinks($content);
|
||||
|
||||
// Does the heavy-lifting for getting "To:" information
|
||||
// FIXME: Make sure NoticeTitle plugin gets a change to add the title to our activityobject!
|
||||
if (Event::handle('StartNoticeSaveWeb', array($this, $this->scoped, &$content, &$options))) {
|
||||
|
||||
ToSelector::fillOptions($this, $options);
|
||||
// FIXME: We should be able to get the attentions from common_render_content!
|
||||
// and maybe even directly save whether they're local or not!
|
||||
$act->context->attention = common_get_attentions($content, $this->scoped, $parent);
|
||||
|
||||
if (Event::handle('StartNoticeSaveWeb', array($this, &$author_id, &$text, &$options))) {
|
||||
// $options gets filled with possible scoping settings
|
||||
ToSelector::fillActivity($this, $act, $options);
|
||||
|
||||
$this->stored = Notice::saveNew($this->scoped->id, $content_shortened, 'web', $options);
|
||||
$actobj = new ActivityObject();
|
||||
$actobj->type = ActivityObject::NOTE;
|
||||
$actobj->content = common_render_content($content, $this->scoped, $parent);
|
||||
|
||||
// Finally add the activity object to our activity
|
||||
$act->objects[] = $actobj;
|
||||
|
||||
$this->stored = Notice::saveActivity($act, $this->scoped, $options);
|
||||
|
||||
if ($upload instanceof MediaFile) {
|
||||
$upload->attachToNotice($this->stored);
|
||||
@@ -193,9 +209,9 @@ class NewnoticeAction extends FormAction
|
||||
Event::handle('EndNoticeSaveWeb', array($this, $this->stored));
|
||||
}
|
||||
|
||||
Event::handle('EndSaveNewNoticeWeb', array($this, $user, &$content_shortened, &$options));
|
||||
Event::handle('EndSaveNewNoticeWeb', array($this, $user, &$content, &$options));
|
||||
|
||||
if (!StatusNet::isAjax()) {
|
||||
if (!GNUsocial::isAjax()) {
|
||||
$url = common_local_url('shownotice', array('notice' => $this->stored->id));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
@@ -203,14 +203,7 @@ class SearchNoticeListItem extends NoticeListItem {
|
||||
{
|
||||
// FIXME: URL, image, video, audio
|
||||
$this->out->elementStart('p', array('class' => 'e-content'));
|
||||
if ($this->notice->rendered) {
|
||||
$this->out->raw($this->highlight($this->notice->rendered, $this->terms));
|
||||
} else {
|
||||
// XXX: may be some uncooked notices in the DB,
|
||||
// we cook them right now. This should probably disappear in future
|
||||
// versions (>> 0.4.x)
|
||||
$this->out->raw($this->highlight(common_render_content($this->notice->content, $this->notice), $this->terms));
|
||||
}
|
||||
$this->out->raw($this->highlight($this->notice->getRendered(), $this->terms));
|
||||
$this->out->elementEnd('p');
|
||||
|
||||
}
|
||||
|
||||
@@ -28,11 +28,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* RSS feed for notice search action class.
|
||||
@@ -48,19 +44,7 @@ require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
*/
|
||||
class NoticesearchrssAction extends Rss10Action
|
||||
{
|
||||
function init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->notices = $this->getNotices();
|
||||
return true;
|
||||
}
|
||||
|
||||
function getNotices($limit=0)
|
||||
protected function getNotices()
|
||||
{
|
||||
$q = $this->trimmed('q');
|
||||
$notices = array();
|
||||
@@ -70,8 +54,7 @@ class NoticesearchrssAction extends Rss10Action
|
||||
$search_engine = $notice->getSearchEngine('notice');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
|
||||
if (!$limit) $limit = 20;
|
||||
$search_engine->limit(0, $limit, true);
|
||||
$search_engine->limit(0, $this->limit, true);
|
||||
if (false === $search_engine->query($q)) {
|
||||
$cnt = 0;
|
||||
} else {
|
||||
|
||||
@@ -27,11 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Show a user's registered OAuth applications
|
||||
@@ -47,19 +43,11 @@ require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||
|
||||
class OauthappssettingsAction extends SettingsAction
|
||||
{
|
||||
var $page = 0;
|
||||
protected $page = null;
|
||||
|
||||
function prepare($args)
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
|
||||
|
||||
if (!common_logged_in()) {
|
||||
// TRANS: Message displayed to an anonymous user trying to view OAuth application list.
|
||||
$this->clientError(_('You must be logged in to list your applications.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
$this->page = $this->int('page') ?: 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,21 +74,13 @@ class OauthappssettingsAction extends SettingsAction
|
||||
return _('Applications you have registered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Content area of the page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$offset = ($this->page - 1) * APPS_PER_PAGE;
|
||||
$limit = APPS_PER_PAGE + 1;
|
||||
|
||||
$application = new Oauth_application();
|
||||
$application->owner = $user->id;
|
||||
$application->owner = $this->scoped->getID();
|
||||
$application->whereAdd("name != 'anonymous'");
|
||||
$application->limit($offset, $limit);
|
||||
$application->orderBy('created DESC');
|
||||
@@ -109,7 +89,7 @@ class OauthappssettingsAction extends SettingsAction
|
||||
$cnt = 0;
|
||||
|
||||
if ($application) {
|
||||
$al = new ApplicationList($application, $user, $this);
|
||||
$al = new ApplicationList($application, $this->scoped, $this);
|
||||
$cnt = $al->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
@@ -135,34 +115,11 @@ class OauthappssettingsAction extends SettingsAction
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
// TRANS: Empty list message on page with OAuth applications.
|
||||
// TRANS: Empty list message on page with OAuth applications. Markup allowed
|
||||
$message = sprintf(_('You have not registered any applications yet.'));
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posts to this form
|
||||
*
|
||||
* Based on the button that was pressed, muxes out to other functions
|
||||
* 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()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Show connected OAuth applications
|
||||
@@ -46,15 +42,14 @@ require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||
*/
|
||||
class OauthconnectionssettingsAction extends SettingsAction
|
||||
{
|
||||
var $page = null;
|
||||
var $oauth_token = null;
|
||||
var $page = null;
|
||||
|
||||
function prepare($args)
|
||||
protected $oauth_token = null;
|
||||
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->oauth_token = $this->arg('oauth_token');
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
|
||||
return true;
|
||||
$this->page = $this->int('page') ?: 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,18 +82,15 @@ class OauthconnectionssettingsAction extends SettingsAction
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$offset = ($this->page - 1) * APPS_PER_PAGE;
|
||||
$limit = APPS_PER_PAGE + 1;
|
||||
|
||||
$connection = $user->getConnectedApps($offset, $limit);
|
||||
$connection = $this->scoped->getConnectedApps($offset, $limit);
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
if (!empty($connection)) {
|
||||
$cal = new ConnectedAppsList($connection, $user, $this);
|
||||
$cal = new ConnectedAppsList($connection, $this->scoped, $this);
|
||||
$cnt = $cal->show();
|
||||
}
|
||||
|
||||
@@ -111,7 +103,7 @@ class OauthconnectionssettingsAction extends SettingsAction
|
||||
$cnt > APPS_PER_PAGE,
|
||||
$this->page,
|
||||
'connectionssettings',
|
||||
array('nickname' => $user->nickname)
|
||||
array('nickname' => $this->scoped->getNickname())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -125,24 +117,14 @@ class OauthconnectionssettingsAction extends SettingsAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
// 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('revoke')) {
|
||||
$this->revokeAccess($this->oauth_token);
|
||||
} else {
|
||||
// TRANS: Client error when submitting a form with unexpected information.
|
||||
$this->clientError(_('Unexpected form submission.'), 401);
|
||||
return $this->revokeAccess($this->oauth_token);
|
||||
}
|
||||
|
||||
// TRANS: Client error when submitting a form with unexpected information.
|
||||
throw new ClientException(_('Unexpected form submission.'), 401);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,11 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Old-school settings
|
||||
@@ -77,35 +73,23 @@ class OldschoolsettingsAction extends SettingsAction
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function prepare($argarray)
|
||||
protected function doPreparation()
|
||||
{
|
||||
if (!common_config('oldschool', 'enabled')) {
|
||||
throw new ClientException("Old-school settings not enabled.");
|
||||
}
|
||||
parent::prepare($argarray);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler method
|
||||
*
|
||||
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
function doPost()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$osp = Old_school_prefs::getKV('user_id', $user->id);
|
||||
$osp = Old_school_prefs::getKV('user_id', $this->scoped->getID());
|
||||
$orig = null;
|
||||
|
||||
if (!empty($osp)) {
|
||||
$orig = clone($osp);
|
||||
} else {
|
||||
$osp = new Old_school_prefs();
|
||||
$osp->user_id = $user->id;
|
||||
$osp->user_id = $this->scoped->getID();
|
||||
$osp->created = common_sql_now();
|
||||
}
|
||||
|
||||
@@ -113,34 +97,25 @@ class OldschoolsettingsAction extends SettingsAction
|
||||
$osp->stream_nicknames = $this->boolean('stream_nicknames');
|
||||
$osp->modified = common_sql_now();
|
||||
|
||||
if (!empty($orig)) {
|
||||
if ($orig instanceof Old_school_prefs) {
|
||||
$osp->update($orig);
|
||||
} else {
|
||||
$osp->insert();
|
||||
}
|
||||
|
||||
// TRANS: Confirmation shown when user profile settings are saved.
|
||||
$this->showForm(_('Settings saved.'), true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$form = new OldSchoolForm($this, $user);
|
||||
$form->show();
|
||||
return _('Settings saved.');
|
||||
}
|
||||
}
|
||||
|
||||
class OldSchoolForm extends Form
|
||||
class OldSchoolSettingsForm extends Form
|
||||
{
|
||||
var $user;
|
||||
|
||||
function __construct($out, $user)
|
||||
function __construct(Action $out)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->user = $user;
|
||||
$this->user = $out->getScoped()->getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,11 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if (!defined('STATUSNET')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Change password
|
||||
@@ -77,18 +73,8 @@ class PasswordsettingsAction extends SettingsAction
|
||||
$this->autofocus('oldpassword');
|
||||
}
|
||||
|
||||
/**
|
||||
* Content area of the page
|
||||
*
|
||||
* Shows a form for changing the password
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$this->elementStart('form', array('method' => 'POST',
|
||||
'id' => 'form_password',
|
||||
'class' => 'form_settings',
|
||||
@@ -102,7 +88,7 @@ class PasswordsettingsAction extends SettingsAction
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
// Users who logged in with OpenID won't have a pwd
|
||||
if ($user->password) {
|
||||
if ($this->scoped->hasPassword()) {
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label on page where to change password.
|
||||
$this->password('oldpassword', _('Old password'));
|
||||
@@ -129,29 +115,8 @@ class PasswordsettingsAction extends SettingsAction
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a post
|
||||
*
|
||||
* Validate input and save changes. Reload the form with a success
|
||||
* or error message.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
assert(!is_null($user)); // should already be checked
|
||||
|
||||
// FIXME: scrub input
|
||||
|
||||
$newpassword = $this->arg('newpassword');
|
||||
@@ -161,49 +126,30 @@ class PasswordsettingsAction extends SettingsAction
|
||||
|
||||
if (strlen($newpassword) < 6) {
|
||||
// TRANS: Form validation error on page where to change password.
|
||||
$this->showForm(_('Password must be 6 or more characters.'));
|
||||
return;
|
||||
throw new ClientException(_('Password must be 6 or more characters.'));
|
||||
} else if (0 != strcmp($newpassword, $confirm)) {
|
||||
// TRANS: Form validation error on password change when password confirmation does not match.
|
||||
$this->showForm(_('Passwords do not match.'));
|
||||
return;
|
||||
throw new ClientException(_('Passwords do not match.'));
|
||||
}
|
||||
|
||||
if ($user->password) {
|
||||
$oldpassword = null;
|
||||
if ($this->scoped->hasPassword()) {
|
||||
$oldpassword = $this->arg('oldpassword');
|
||||
|
||||
if (!common_check_user($user->nickname, $oldpassword)) {
|
||||
if (!common_check_user($this->scoped->getNickname(), $oldpassword)) {
|
||||
// TRANS: Form validation error on page where to change password.
|
||||
$this->showForm(_('Incorrect old password.'));
|
||||
return;
|
||||
throw new ClientException(_('Incorrect old password.'));
|
||||
}
|
||||
}else{
|
||||
$oldpassword = null;
|
||||
}
|
||||
|
||||
$success = false;
|
||||
if(Event::handle('StartChangePassword', array($user, $oldpassword, $newpassword))){
|
||||
if (Event::handle('StartChangePassword', array($this->scoped, $oldpassword, $newpassword))) {
|
||||
//no handler changed the password, so change the password internally
|
||||
$original = clone($user);
|
||||
$user->setPassword($newpassword);
|
||||
|
||||
$user->password = common_munge_password($newpassword, $user->id);
|
||||
|
||||
$val = $user->validate();
|
||||
if ($val !== true) {
|
||||
// TRANS: Form validation error on page where to change password.
|
||||
$this->showForm(_('Error saving user; invalid.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$user->update($original)) {
|
||||
// TRANS: Server error displayed on page where to change password when password change
|
||||
// TRANS: could not be made because of a server error.
|
||||
$this->serverError(_('Cannot save new password.'));
|
||||
}
|
||||
Event::handle('EndChangePassword', array($user));
|
||||
Event::handle('EndChangePassword', array($this->scoped));
|
||||
}
|
||||
|
||||
// TRANS: Form validation notice on page where to change password.
|
||||
$this->showForm(_('Password saved.'), true);
|
||||
return _('Password saved.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,8 +417,6 @@ class PathsAdminPanelForm extends AdminForm
|
||||
|
||||
// TRANS: Drop down option in Paths admin panel (option for "When to use SSL").
|
||||
$ssl = array('never' => _('Never'),
|
||||
// TRANS: Drop down option in Paths admin panel (option for "When to use SSL").
|
||||
'sometimes' => _('Sometimes'),
|
||||
// TRANS: Drop down option in Paths admin panel (option for "When to use SSL").
|
||||
'always' => _('Always'));
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class PeopletagautocompleteAction extends Action
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$tags = $profile->getLists(common_current_user());
|
||||
$tags = $profile->getLists($this->scoped);
|
||||
|
||||
$this->tags = array();
|
||||
while ($tags->fetch()) {
|
||||
|
||||
@@ -116,7 +116,7 @@ class PeopletagsbyuserAction extends Action
|
||||
|
||||
$user = common_current_user();
|
||||
if ($this->arg('public')) {
|
||||
$this->tags = $this->tagger->getLists(false, $offset, $limit);
|
||||
$this->tags = $this->tagger->getLists(null, $offset, $limit);
|
||||
} else if ($this->arg('private')) {
|
||||
if (empty($user)) {
|
||||
// TRANS: Error message displayed when trying to perform an action that requires a logged in user.
|
||||
@@ -130,7 +130,7 @@ class PeopletagsbyuserAction extends Action
|
||||
$this->clientError(_('You cannot view others\' private lists'), 403);
|
||||
}
|
||||
} else {
|
||||
$this->tags = $this->tagger->getLists(common_current_user(), $offset, $limit);
|
||||
$this->tags = $this->tagger->getLists($this->scoped, $offset, $limit);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ class PeopletagsforuserAction extends Action
|
||||
$offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
|
||||
$limit = PEOPLETAGS_PER_PAGE + 1;
|
||||
|
||||
$ptags = $this->tagged->getOtherTags(common_current_user(), $offset, $limit);
|
||||
$ptags = $this->tagged->getOtherTags($this->scoped, $offset, $limit);
|
||||
|
||||
$pl = new PeopletagList($ptags, $this);
|
||||
$cnt = $pl->show();
|
||||
|
||||
@@ -62,7 +62,7 @@ class PluginsadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
// TRANS: Instructions at top of plugin admin page.
|
||||
return _('Additional plugins can be enabled and configured manually. ' .
|
||||
'See the <a href="http://status.net/wiki/Plugins">online plugin ' .
|
||||
'See the <a href="https://git.gnu.io/gnu/gnu-social/blob/master/plugins/README.md">online plugin ' .
|
||||
'documentation</a> for more details.');
|
||||
}
|
||||
|
||||
|
||||
@@ -82,8 +82,7 @@ class ProfilesettingsAction extends SettingsAction
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_profile',
|
||||
@@ -100,21 +99,26 @@ class ProfilesettingsAction extends SettingsAction
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label in form for profile settings.
|
||||
$this->input('nickname', _('Nickname'),
|
||||
$this->arg('nickname') ?: $profile->nickname,
|
||||
$this->trimmed('nickname') ?: $this->scoped->getNickname(),
|
||||
// TRANS: Tooltip for field label in form for profile settings.
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces.'),
|
||||
null, false, // "name" (will be set to id), then "required"
|
||||
!common_config('profile', 'changenick') ? array('disabled'=>'disabled') : array());
|
||||
!common_config('profile', 'changenick')
|
||||
? array('disabled' => 'disabled', 'placeholder' => null)
|
||||
: array('placeholder' => null));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label in form for profile settings.
|
||||
$this->input('fullname', _('Full name'),
|
||||
($this->arg('fullname')) ? $this->arg('fullname') : $profile->fullname);
|
||||
$this->trimmed('fullname') ?: $this->scoped->getFullname(),
|
||||
// TRANS: Instructions for full name text field on profile settings
|
||||
_('A full name is required, if empty it will be set to your nickname.'),
|
||||
null, true);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label in form for profile settings.
|
||||
$this->input('homepage', _('Homepage'),
|
||||
($this->arg('homepage')) ? $this->arg('homepage') : $profile->homepage,
|
||||
$this->trimmed('homepage') ?: $this->scoped->getHomepage(),
|
||||
// TRANS: Tooltip for field label in form for profile settings.
|
||||
_('URL of your homepage, blog, or profile on another site.'));
|
||||
$this->elementEnd('li');
|
||||
@@ -135,13 +139,13 @@ class ProfilesettingsAction extends SettingsAction
|
||||
// TRANS: Text area label in form for profile settings where users can provide
|
||||
// TRANS: their biography.
|
||||
$this->textarea('bio', _('Bio'),
|
||||
($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
|
||||
$this->trimmed('bio') ?: $this->scoped->getDescription(),
|
||||
$bioInstr);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label in form for profile settings.
|
||||
$this->input('location', _('Location'),
|
||||
($this->arg('location')) ? $this->arg('location') : $profile->location,
|
||||
$this->trimmed('location') ?: $this->scoped->location,
|
||||
// TRANS: Tooltip for field label in form for profile settings.
|
||||
_('Where you are, like "City, State (or Region), Country".'));
|
||||
$this->elementEnd('li');
|
||||
@@ -150,14 +154,14 @@ class ProfilesettingsAction extends SettingsAction
|
||||
// TRANS: Checkbox label in form for profile settings.
|
||||
$this->checkbox('sharelocation', _('Share my current location when posting notices'),
|
||||
($this->arg('sharelocation')) ?
|
||||
$this->arg('sharelocation') : $this->scoped->shareLocation());
|
||||
$this->boolean('sharelocation') : $this->scoped->shareLocation());
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
Event::handle('EndProfileFormData', array($this));
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label in form for profile settings.
|
||||
$this->input('tags', _('Tags'),
|
||||
($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
|
||||
$this->trimmed('tags') ?: implode(' ', Profile_tag::getSelfTagsArray($this->scoped)),
|
||||
// TRANS: Tooltip for field label in form for profile settings.
|
||||
_('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated.'));
|
||||
$this->elementEnd('li');
|
||||
@@ -203,13 +207,15 @@ class ProfilesettingsAction extends SettingsAction
|
||||
(empty($user->subscribe_policy)) ? User::SUBSCRIBE_POLICY_OPEN : $user->subscribe_policy);
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('private_stream',
|
||||
// TRANS: Checkbox label in profile settings.
|
||||
_('Make updates visible only to my followers'),
|
||||
($this->arg('private_stream')) ?
|
||||
$this->boolean('private_stream') : $user->private_stream);
|
||||
$this->elementEnd('li');
|
||||
if (common_config('profile', 'allowprivate') || $user->private_stream) {
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('private_stream',
|
||||
// TRANS: Checkbox label in profile settings.
|
||||
_('Make updates visible only to my followers'),
|
||||
($this->arg('private_stream')) ?
|
||||
$this->boolean('private_stream') : $user->private_stream);
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
// TRANS: Button to save input in profile settings.
|
||||
$this->submit('save', _m('BUTTON','Save'));
|
||||
@@ -226,17 +232,8 @@ class ProfilesettingsAction extends SettingsAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
// TRANS: Form validation error.
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Event::handle('StartProfileSaveForm', array($this))) {
|
||||
|
||||
// $nickname will only be set if this changenick value is true.
|
||||
@@ -244,15 +241,13 @@ class ProfilesettingsAction extends SettingsAction
|
||||
try {
|
||||
$nickname = Nickname::normalize($this->trimmed('nickname'), true);
|
||||
} catch (NicknameTakenException $e) {
|
||||
// Abort only if the nickname is occupied by another local profile
|
||||
if ($e->profile->id != $this->scoped->id) {
|
||||
$this->showForm($e->getMessage());
|
||||
return;
|
||||
// Abort only if the nickname is occupied by _another_ local user profile
|
||||
if (!$this->scoped->sameAs($e->profile)) {
|
||||
throw $e;
|
||||
}
|
||||
$nickname = Nickname::normalize($this->trimmed('nickname')); // without in-use check this time
|
||||
} catch (NicknameException $e) {
|
||||
$this->showForm($e->getMessage());
|
||||
return;
|
||||
// Since the variable wasn't set before the exception was thrown, let's run
|
||||
// the normalize sequence again, but without in-use check this time.
|
||||
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,9 +255,8 @@ class ProfilesettingsAction extends SettingsAction
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$bio = $this->trimmed('bio');
|
||||
$location = $this->trimmed('location');
|
||||
$autosubscribe = $this->boolean('autosubscribe');
|
||||
$autosubscribe = $this->booleanintstring('autosubscribe');
|
||||
$subscribe_policy = $this->trimmed('subscribe_policy');
|
||||
$private_stream = $this->boolean('private_stream');
|
||||
$language = $this->trimmed('language');
|
||||
$timezone = $this->trimmed('timezone');
|
||||
$tagstring = $this->trimmed('tags');
|
||||
@@ -271,33 +265,27 @@ class ProfilesettingsAction extends SettingsAction
|
||||
if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!common_valid_http_url($homepage)) {
|
||||
// TRANS: Validation error in form for profile settings.
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
throw new ClientException(_('Homepage is not a valid URL.'));
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 191) {
|
||||
// TRANS: Validation error in form for profile settings.
|
||||
$this->showForm(_('Full name is too long (maximum 255 characters).'));
|
||||
return;
|
||||
throw new ClientException(_('Full name is too long (maximum 191 characters).'));
|
||||
} else if (Profile::bioTooLong($bio)) {
|
||||
// TRANS: Validation error in form for profile settings.
|
||||
// TRANS: Plural form is used based on the maximum number of allowed
|
||||
// TRANS: characters for the biography (%d).
|
||||
$this->showForm(sprintf(_m('Bio is too long (maximum %d character).',
|
||||
throw new ClientException(sprintf(_m('Bio is too long (maximum %d character).',
|
||||
'Bio is too long (maximum %d characters).',
|
||||
Profile::maxBio()),
|
||||
Profile::maxBio()));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
} else if (!is_null($location) && mb_strlen($location) > 191) {
|
||||
// TRANS: Validation error in form for profile settings.
|
||||
$this->showForm(_('Location is too long (maximum 255 characters).'));
|
||||
return;
|
||||
throw new ClientException(_('Location is too long (maximum 191 characters).'));
|
||||
} else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) {
|
||||
// TRANS: Validation error in form for profile settings.
|
||||
$this->showForm(_('Timezone not selected.'));
|
||||
return;
|
||||
throw new ClientException(_('Timezone not selected.'));
|
||||
} else if (!is_null($language) && strlen($language) > 50) {
|
||||
// TRANS: Validation error in form for profile settings.
|
||||
$this->showForm(_('Language is too long (maximum 50 characters).'));
|
||||
return;
|
||||
throw new ClientException(_('Language is too long (maximum 50 characters).'));
|
||||
}
|
||||
|
||||
$tags = array();
|
||||
@@ -313,17 +301,25 @@ class ProfilesettingsAction extends SettingsAction
|
||||
if (!common_valid_profile_tag($tag)) {
|
||||
// TRANS: Validation error in form for profile settings.
|
||||
// TRANS: %s is an invalid tag.
|
||||
$this->showForm(sprintf(_('Invalid tag: "%s".'), $tag));
|
||||
return;
|
||||
throw new ClientException(sprintf(_('Invalid tag: "%s".'), $tag));
|
||||
}
|
||||
|
||||
$tag_priv[$tag] = $private;
|
||||
}
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
$user = $this->scoped->getUser();
|
||||
$user->query('BEGIN');
|
||||
|
||||
// Only allow setting private_stream if site policy allows it
|
||||
// (or user already _has_ a private stream, then you can unset it)
|
||||
if (common_config('profile', 'allowprivate') || $user->private_stream) {
|
||||
$private_stream = $this->booleanintstring('private_stream');
|
||||
} else {
|
||||
// if not allowed, we set to the existing value
|
||||
$private_stream = $user->private_stream;
|
||||
}
|
||||
|
||||
// $user->nickname is updated through Profile->update();
|
||||
|
||||
// XXX: XOR
|
||||
@@ -344,61 +340,60 @@ class ProfilesettingsAction extends SettingsAction
|
||||
$result = $user->update($original);
|
||||
if ($result === false) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
$user->query('ROLLBACK');
|
||||
// TRANS: Server error thrown when user profile settings could not be updated to
|
||||
// TRANS: automatically subscribe to any subscriber.
|
||||
$this->serverError(_('Could not update user for autosubscribe or subscribe_policy.'));
|
||||
throw new ServerException(_('Could not update user for autosubscribe or subscribe_policy.'));
|
||||
}
|
||||
|
||||
// Re-initialize language environment if it changed
|
||||
common_init_language();
|
||||
}
|
||||
|
||||
$profile = $user->getProfile();
|
||||
$original = clone($this->scoped);
|
||||
|
||||
$orig_profile = clone($profile);
|
||||
|
||||
if (common_config('profile', 'changenick') == true && $profile->nickname !== $nickname) {
|
||||
if (common_config('profile', 'changenick') == true && $this->scoped->getNickname() !== $nickname) {
|
||||
assert(Nickname::normalize($nickname)===$nickname);
|
||||
common_debug("Changing user nickname from '{$profile->nickname}' to '{$nickname}'.");
|
||||
$profile->nickname = $nickname;
|
||||
$profile->profileurl = common_profile_url($profile->nickname);
|
||||
common_debug("Changing user nickname from '{$this->scoped->getNickname()}' to '{$nickname}'.");
|
||||
$this->scoped->nickname = $nickname;
|
||||
$this->scoped->profileurl = common_profile_url($this->scoped->getNickname());
|
||||
}
|
||||
$profile->fullname = $fullname;
|
||||
$profile->homepage = $homepage;
|
||||
$profile->bio = $bio;
|
||||
$profile->location = $location;
|
||||
$this->scoped->fullname = (mb_strlen($fullname)>0 ? $fullname : $this->scoped->nickname);
|
||||
$this->scoped->homepage = $homepage;
|
||||
$this->scoped->bio = $bio;
|
||||
$this->scoped->location = $location;
|
||||
|
||||
$loc = Location::fromName($location);
|
||||
|
||||
if (empty($loc)) {
|
||||
$profile->lat = null;
|
||||
$profile->lon = null;
|
||||
$profile->location_id = null;
|
||||
$profile->location_ns = null;
|
||||
$this->scoped->lat = null;
|
||||
$this->scoped->lon = null;
|
||||
$this->scoped->location_id = null;
|
||||
$this->scoped->location_ns = null;
|
||||
} else {
|
||||
$profile->lat = $loc->lat;
|
||||
$profile->lon = $loc->lon;
|
||||
$profile->location_id = $loc->location_id;
|
||||
$profile->location_ns = $loc->location_ns;
|
||||
$this->scoped->lat = $loc->lat;
|
||||
$this->scoped->lon = $loc->lon;
|
||||
$this->scoped->location_id = $loc->location_id;
|
||||
$this->scoped->location_ns = $loc->location_ns;
|
||||
}
|
||||
|
||||
if (common_config('location', 'share') == 'user') {
|
||||
|
||||
$exists = false;
|
||||
|
||||
$prefs = User_location_prefs::getKV('user_id', $user->id);
|
||||
$prefs = User_location_prefs::getKV('user_id', $this->scoped->getID());
|
||||
|
||||
if (empty($prefs)) {
|
||||
$prefs = new User_location_prefs();
|
||||
|
||||
$prefs->user_id = $user->id;
|
||||
$prefs->user_id = $this->scoped->getID();
|
||||
$prefs->created = common_sql_now();
|
||||
} else {
|
||||
$exists = true;
|
||||
$orig = clone($prefs);
|
||||
}
|
||||
|
||||
$prefs->share_location = $this->boolean('sharelocation');
|
||||
$prefs->share_location = $this->booleanintstring('sharelocation');
|
||||
|
||||
if ($exists) {
|
||||
$result = $prefs->update($orig);
|
||||
@@ -408,42 +403,37 @@ class ProfilesettingsAction extends SettingsAction
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($prefs, ($exists) ? 'UPDATE' : 'INSERT', __FILE__);
|
||||
$user->query('ROLLBACK');
|
||||
// TRANS: Server error thrown when user profile location preference settings could not be updated.
|
||||
$this->serverError(_('Could not save location prefs.'));
|
||||
throw new ServerException(_('Could not save location prefs.'));
|
||||
}
|
||||
}
|
||||
|
||||
common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__);
|
||||
common_debug('New profile: ' . common_log_objstring($profile), __FILE__);
|
||||
common_debug('Old profile: ' . common_log_objstring($original), __FILE__);
|
||||
common_debug('New profile: ' . common_log_objstring($this->scoped), __FILE__);
|
||||
|
||||
$result = $profile->update($orig_profile);
|
||||
$result = $this->scoped->update($original);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($profile, 'UPDATE', __FILE__);
|
||||
common_log_db_error($this->scoped, 'UPDATE', __FILE__);
|
||||
$user->query('ROLLBACK');
|
||||
// TRANS: Server error thrown when user profile settings could not be saved.
|
||||
$this->serverError(_('Could not save profile.'));
|
||||
throw new ServerException(_('Could not save profile.'));
|
||||
}
|
||||
|
||||
// Set the user tags
|
||||
$result = $user->setSelfTags($tags, $tag_priv);
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server error thrown when user profile settings tags could not be saved.
|
||||
$this->serverError(_('Could not save tags.'));
|
||||
}
|
||||
$result = Profile_tag::setSelfTags($this->scoped, $tags, $tag_priv);
|
||||
|
||||
$user->query('COMMIT');
|
||||
Event::handle('EndProfileSaveForm', array($this));
|
||||
|
||||
// TRANS: Confirmation shown when user profile settings are saved.
|
||||
$this->showForm(_('Settings saved.'), true);
|
||||
return _('Settings saved.');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function showAside() {
|
||||
$user = common_current_user();
|
||||
|
||||
$this->elementStart('div', array('id' => 'aside_primary',
|
||||
'class' => 'aside'));
|
||||
|
||||
@@ -451,7 +441,7 @@ class ProfilesettingsAction extends SettingsAction
|
||||
'class' => 'section'));
|
||||
$this->elementStart('ul');
|
||||
if (Event::handle('StartProfileSettingsActions', array($this))) {
|
||||
if ($user->hasRight(Right::BACKUPACCOUNT)) {
|
||||
if ($this->scoped->hasRight(Right::BACKUPACCOUNT)) {
|
||||
$this->elementStart('li');
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('backupaccount')),
|
||||
@@ -459,7 +449,7 @@ class ProfilesettingsAction extends SettingsAction
|
||||
_('Backup account'));
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
if ($user->hasRight(Right::DELETEACCOUNT)) {
|
||||
if ($this->scoped->hasRight(Right::DELETEACCOUNT)) {
|
||||
$this->elementStart('li');
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('deleteaccount')),
|
||||
@@ -467,7 +457,7 @@ class ProfilesettingsAction extends SettingsAction
|
||||
_('Delete account'));
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
if ($user->hasRight(Right::RESTOREACCOUNT)) {
|
||||
if ($this->scoped->hasRight(Right::RESTOREACCOUNT)) {
|
||||
$this->elementStart('li');
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('restoreaccount')),
|
||||
|
||||
+25
-161
@@ -29,10 +29,6 @@
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
// Farther than any human will go
|
||||
|
||||
define('MAX_PUBLIC_PAGE', 100);
|
||||
|
||||
/**
|
||||
* Action for displaying the public stream
|
||||
*
|
||||
@@ -43,54 +39,9 @@ define('MAX_PUBLIC_PAGE', 100);
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see PublicrssAction
|
||||
* @see PublicxrdsAction
|
||||
*/
|
||||
class PublicAction extends ManagedAction
|
||||
class PublicAction extends SitestreamAction
|
||||
{
|
||||
/**
|
||||
* page of the stream we're on; default = 1
|
||||
*/
|
||||
|
||||
var $page = null;
|
||||
var $notice;
|
||||
|
||||
protected $stream = null;
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function doPreparation()
|
||||
{
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||
|
||||
if ($this->page > MAX_PUBLIC_PAGE) {
|
||||
// TRANS: Client error displayed when requesting a public timeline page beyond the page limit.
|
||||
// TRANS: %s is the page limit.
|
||||
$this->clientError(sprintf(_('Beyond the page limit (%s).'), MAX_PUBLIC_PAGE));
|
||||
}
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
$this->streamPrepare();
|
||||
|
||||
$this->notice = $this->stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1);
|
||||
|
||||
if (!$this->notice) {
|
||||
// TRANS: Server error displayed when a public timeline cannot be retrieved.
|
||||
$this->serverError(_('Could not retrieve public timeline.'));
|
||||
}
|
||||
|
||||
if ($this->page > 1 && $this->notice->N == 0){
|
||||
// TRANS: Client error when page not found (404).
|
||||
$this->clientError(_('No such page.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function streamPrepare()
|
||||
{
|
||||
if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
|
||||
@@ -117,100 +68,6 @@ class PublicAction extends ManagedAction
|
||||
}
|
||||
}
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
parent::extraHead();
|
||||
$this->element('meta', array('http-equiv' => 'X-XRDS-Location',
|
||||
'content' => common_local_url('publicxrds')));
|
||||
|
||||
$rsd = common_local_url('rsd');
|
||||
|
||||
// RSD, http://tales.phrasewise.com/rfc/rsd
|
||||
|
||||
$this->element('link', array('rel' => 'EditURI',
|
||||
'type' => 'application/rsd+xml',
|
||||
'href' => $rsd));
|
||||
|
||||
if ($this->page != 1) {
|
||||
$this->element('link', array('rel' => 'canonical',
|
||||
'href' => common_local_url('public')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output <head> elements for RSS and Atom feeds
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function getFeeds()
|
||||
{
|
||||
return array(new Feed(Feed::JSON,
|
||||
common_local_url('ApiTimelinePublic',
|
||||
array('format' => 'as')),
|
||||
// TRANS: Link description for public timeline feed.
|
||||
_('Public Timeline Feed (Activity Streams JSON)')),
|
||||
new Feed(Feed::RSS1, common_local_url('publicrss'),
|
||||
// TRANS: Link description for public timeline feed.
|
||||
_('Public Timeline Feed (RSS 1.0)')),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('ApiTimelinePublic',
|
||||
array('format' => 'rss')),
|
||||
// TRANS: Link description for public timeline feed.
|
||||
_('Public Timeline Feed (RSS 2.0)')),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('ApiTimelinePublic',
|
||||
array('format' => 'atom')),
|
||||
// TRANS: Link description for public timeline feed.
|
||||
_('Public Timeline Feed (Atom)')));
|
||||
}
|
||||
|
||||
function showEmptyList()
|
||||
{
|
||||
// TRANS: Text displayed for public feed when there are no public notices.
|
||||
$message = _('This is the public timeline for %%site.name%% but no one has posted anything yet.') . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
// TRANS: Additional text displayed for public feed when there are no public notices for a logged in user.
|
||||
$message .= _('Be the first to post!');
|
||||
}
|
||||
else {
|
||||
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||
// TRANS: Additional text displayed for public feed when there are no public notices for a not logged in user.
|
||||
$message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the content area
|
||||
*
|
||||
* Shows a list of the notices in the public stream, with some pagination
|
||||
* controls.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
|
||||
$nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
|
||||
} else {
|
||||
$nl = new ThreadedNoticeList($this->notice, $this, $this->scoped);
|
||||
}
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
if ($cnt == 0) {
|
||||
$this->showEmptyList();
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, $this->action);
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
// Show invite button, as long as site isn't closed, and
|
||||
@@ -239,23 +96,30 @@ class PublicAction extends ManagedAction
|
||||
$feat->show();
|
||||
}
|
||||
|
||||
function showAnonymousMessage()
|
||||
/**
|
||||
* Output <head> elements for RSS and Atom feeds
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function getFeeds()
|
||||
{
|
||||
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||
// TRANS: Message for not logged in users at an invite-only site trying to view the public feed of notices.
|
||||
// TRANS: This message contains Markdown links. Please mind the formatting.
|
||||
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [StatusNet](http://status.net/) tool. ' .
|
||||
'[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ' .
|
||||
'([Read more](%%doc.help%%))');
|
||||
} else {
|
||||
// TRANS: Message for not logged in users at a closed site trying to view the public feed of notices.
|
||||
// TRANS: This message contains Markdown links. Please mind the formatting.
|
||||
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [StatusNet](http://status.net/) tool.');
|
||||
}
|
||||
$this->elementStart('div', array('id' => 'anon_notice'));
|
||||
$this->raw(common_markup_to_html($m));
|
||||
$this->elementEnd('div');
|
||||
return array(new Feed(Feed::JSON,
|
||||
common_local_url('ApiTimelinePublic',
|
||||
array('format' => 'as')),
|
||||
// TRANS: Link description for public timeline feed.
|
||||
_('Public Timeline Feed (Activity Streams JSON)')),
|
||||
new Feed(Feed::RSS1, common_local_url('publicrss'),
|
||||
// TRANS: Link description for public timeline feed.
|
||||
_('Public Timeline Feed (RSS 1.0)')),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('ApiTimelinePublic',
|
||||
array('format' => 'rss')),
|
||||
// TRANS: Link description for public timeline feed.
|
||||
_('Public Timeline Feed (RSS 2.0)')),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('ApiTimelinePublic',
|
||||
array('format' => 'atom')),
|
||||
// TRANS: Link description for public timeline feed.
|
||||
_('Public Timeline Feed (Atom)')));
|
||||
}
|
||||
}
|
||||
|
||||
+4
-36
@@ -28,11 +28,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* RSS feed for public timeline.
|
||||
@@ -48,29 +44,6 @@ require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
*/
|
||||
class PublicrssAction extends Rss10Action
|
||||
{
|
||||
/**
|
||||
* Read arguments and initialize members
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
* @return boolean success
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->notices = $this->getNotices($this->limit);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
@@ -78,15 +51,10 @@ class PublicrssAction extends Rss10Action
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices($limit=0)
|
||||
protected function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
$notice = Notice::publicStream(0, ($limit == 0) ? 48 : $limit);
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
$stream = Notice::publicStream(0, $this->limit);
|
||||
return $stream->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -272,10 +272,16 @@ class RecoverpasswordAction extends Action
|
||||
try {
|
||||
User::recoverPassword($nore);
|
||||
$this->mode = 'sent';
|
||||
// TRANS: User notification after an e-mail with instructions was sent from the password recovery form.
|
||||
$this->msg = _('Instructions for recovering your password ' .
|
||||
'have been sent to the email address registered to your ' .
|
||||
'account.');
|
||||
if (common_is_email($nore) && common_config('site', 'fakeaddressrecovery')) {
|
||||
// TRANS: User notification when recovering password by giving email address,
|
||||
// regardless if the mail was sent or not (to hide registered email status).
|
||||
$this->msg = _('If the email address you provided was found in the database, a recovery mail with instructions has been sent there.');
|
||||
} else {
|
||||
// TRANS: User notification after an e-mail with instructions was sent from the password recovery form.
|
||||
$this->msg = _('Instructions for recovering your password ' .
|
||||
'have been sent to the email address registered to your ' .
|
||||
'account.');
|
||||
}
|
||||
$this->success = true;
|
||||
} catch (Exception $e) {
|
||||
$this->success = false;
|
||||
@@ -316,16 +322,7 @@ class RecoverpasswordAction extends Action
|
||||
}
|
||||
|
||||
// OK, we're ready to go
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
$user->password = common_munge_password($newpassword, $user->id);
|
||||
|
||||
if (!$user->update($original)) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
// TRANS: Reset password form validation error message.
|
||||
$this->serverError(_('Cannot save new password.'));
|
||||
}
|
||||
$user->setPassword($newpassword);
|
||||
|
||||
$this->clearTempUser();
|
||||
|
||||
|
||||
@@ -28,11 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Redirect to a given URL
|
||||
@@ -47,75 +43,27 @@ if (!defined('STATUSNET')) {
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class RedirecturlAction extends Action
|
||||
class RedirecturlAction extends ManagedAction
|
||||
{
|
||||
protected $id = null;
|
||||
protected $file = null;
|
||||
|
||||
/**
|
||||
* For initializing members of the class.
|
||||
*
|
||||
* @param array $argarray misc. arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function prepare($argarray)
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($argarray);
|
||||
|
||||
$this->id = $this->trimmed('id');
|
||||
|
||||
if (empty($this->id)) {
|
||||
// TRANS: Client exception thrown when no ID parameter was provided.
|
||||
throw new ClientException(_('No id parameter.'));
|
||||
}
|
||||
|
||||
$this->file = File::getKV('id', $this->id);
|
||||
|
||||
if (empty($this->file)) {
|
||||
// TRANS: Client exception thrown when an invalid ID parameter was provided for a file.
|
||||
// TRANS: %d is the provided ID for which the file is not present (number).
|
||||
throw new ClientException(sprintf(_('No such file "%d".'),
|
||||
$this->id),
|
||||
404);
|
||||
}
|
||||
$this->file = File::getByID($this->int('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler method
|
||||
*
|
||||
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($argarray=null)
|
||||
public function showPage()
|
||||
{
|
||||
common_redirect($this->file->url, 307);
|
||||
common_redirect($this->file->getUrl(false), 301);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last modified, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string last modified http header
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
// For comparison with If-Last-Modified
|
||||
@@ -133,9 +81,9 @@ class RedirecturlAction extends Action
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
return 'W/"' . implode(':', array($this->arg('action'),
|
||||
return 'W/"' . implode(':', array($this->getActionName(),
|
||||
common_user_cache_hash(),
|
||||
common_language(),
|
||||
$this->file->id)) . '"';
|
||||
$this->file->getID())) . '"';
|
||||
}
|
||||
}
|
||||
|
||||
+31
-36
@@ -27,9 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); }
|
||||
|
||||
/**
|
||||
* An action for registering a new user account
|
||||
@@ -133,7 +131,11 @@ class RegisterAction extends Action
|
||||
// TRANS: Client error displayed when trying to register while already logged in.
|
||||
$this->clientError(_('Already logged in.'));
|
||||
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->tryRegister();
|
||||
try {
|
||||
$this->tryRegister();
|
||||
} catch (ClientException $e) {
|
||||
$this->showForm($e->getMessage());
|
||||
}
|
||||
} else {
|
||||
$this->showForm();
|
||||
}
|
||||
@@ -210,9 +212,6 @@ class RegisterAction extends Action
|
||||
!common_valid_http_url($homepage)) {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid homepage URL.
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
} 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->showForm(_('Full name is too long (maximum 255 characters).'));
|
||||
} else if (Profile::bioTooLong($bio)) {
|
||||
// TRANS: Form validation error on registration page when providing too long a bio text.
|
||||
// TRANS: %d is the maximum number of characters for bio; used for plural.
|
||||
@@ -220,49 +219,44 @@ class RegisterAction extends Action
|
||||
'Bio is too long (maximum %d characters).',
|
||||
Profile::maxBio()),
|
||||
Profile::maxBio()));
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
// TRANS: Form validation error displayed when trying to register with a too long location.
|
||||
$this->showForm(_('Location is too long (maximum 255 characters).'));
|
||||
} else if (strlen($password) < 6) {
|
||||
// TRANS: Form validation error displayed when trying to register with too short a password.
|
||||
$this->showForm(_('Password must be 6 or more characters.'));
|
||||
} else if ($password != $confirm) {
|
||||
// TRANS: Form validation error displayed when trying to register with non-matching passwords.
|
||||
$this->showForm(_('Passwords do not match.'));
|
||||
} else if ($user = User::register(array('nickname' => $nickname,
|
||||
} else {
|
||||
try {
|
||||
$user = User::register(array('nickname' => $nickname,
|
||||
'password' => $password,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'bio' => $bio,
|
||||
'location' => $location,
|
||||
'code' => $code))) {
|
||||
if (!($user instanceof User)) {
|
||||
'code' => $code));
|
||||
// success!
|
||||
if (!common_set_user($user)) {
|
||||
// TRANS: Server error displayed when saving fails during user registration.
|
||||
$this->serverError(_('Error setting user.'));
|
||||
}
|
||||
// this is a real login
|
||||
common_real_login(true);
|
||||
if ($this->boolean('rememberme')) {
|
||||
common_debug('Adding rememberme cookie for ' . $nickname);
|
||||
common_rememberme($user);
|
||||
}
|
||||
|
||||
// Re-init language env in case it changed (not yet, but soon)
|
||||
common_init_language();
|
||||
|
||||
Event::handle('EndRegistrationTry', array($this));
|
||||
|
||||
$this->showSuccess();
|
||||
} catch (Exception $e) {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
return;
|
||||
$this->showForm($e->getMessage());
|
||||
}
|
||||
// success!
|
||||
if (!common_set_user($user)) {
|
||||
// TRANS: Server error displayed when saving fails during user registration.
|
||||
$this->serverError(_('Error setting user.'));
|
||||
}
|
||||
// this is a real login
|
||||
common_real_login(true);
|
||||
if ($this->boolean('rememberme')) {
|
||||
common_debug('Adding rememberme cookie for ' . $nickname);
|
||||
common_rememberme($user);
|
||||
}
|
||||
|
||||
// Re-init language env in case it changed (not yet, but soon)
|
||||
common_init_language();
|
||||
|
||||
Event::handle('EndRegistrationTry', array($this));
|
||||
|
||||
$this->showSuccess();
|
||||
} else {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,6 +483,7 @@ class RegisterAction extends Action
|
||||
'id' => 'license',
|
||||
'class' => 'checkbox',
|
||||
'name' => 'license',
|
||||
'required' => 'true',
|
||||
'value' => 'true');
|
||||
if ($this->boolean('license')) {
|
||||
$attrs['checked'] = 'checked';
|
||||
|
||||
+24
-101
@@ -27,13 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* List of replies
|
||||
@@ -44,72 +38,11 @@ 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
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class RepliesAction extends Action
|
||||
class RepliesAction extends ShowstreamAction
|
||||
{
|
||||
var $page = null;
|
||||
var $notice;
|
||||
|
||||
/**
|
||||
* Prepare the object
|
||||
*
|
||||
* Check the input values and initialize the object.
|
||||
* Shows an error page on bad input.
|
||||
*
|
||||
* @param array $args $_REQUEST data
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
public function getStream()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$nickname = common_canonical_nickname($this->arg('nickname'));
|
||||
|
||||
$this->user = User::getKV('nickname', $nickname);
|
||||
|
||||
if (!$this->user) {
|
||||
// TRANS: Client error displayed when trying to reply to a non-exsting user.
|
||||
$this->clientError(_('No such user.'));
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if (!$profile) {
|
||||
// TRANS: Error message displayed when referring to a user without a profile.
|
||||
$this->serverError(_('User has no profile.'));
|
||||
}
|
||||
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
$stream = new ReplyNoticeStream($this->user->id,
|
||||
Profile::current());
|
||||
|
||||
$this->notice = $stream->getNotices(($this->page-1) * NOTICES_PER_PAGE,
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* Just show the page. All args already handled.
|
||||
*
|
||||
* @param array $args $_REQUEST data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showPage();
|
||||
return new ReplyNoticeStream($this->target->getID(), $this->scoped);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,12 +57,12 @@ class RepliesAction extends Action
|
||||
if ($this->page == 1) {
|
||||
// TRANS: Title for first page of replies for a user.
|
||||
// TRANS: %s is a user nickname.
|
||||
return sprintf(_("Replies to %s"), $this->user->nickname);
|
||||
return sprintf(_("Replies to %s"), $this->target->getNickname());
|
||||
} else {
|
||||
// TRANS: Title for all but the first page of replies for a user.
|
||||
// TRANS: %1$s is a user nickname, %2$d is a page number.
|
||||
return sprintf(_('Replies to %1$s, page %2$d'),
|
||||
$this->user->nickname,
|
||||
$this->target->getNickname(),
|
||||
$this->page);
|
||||
}
|
||||
}
|
||||
@@ -144,46 +77,39 @@ class RepliesAction extends Action
|
||||
return array(new Feed(Feed::JSON,
|
||||
common_local_url('ApiTimelineMentions',
|
||||
array(
|
||||
'id' => $this->user->nickname,
|
||||
'id' => $this->target->getNickname(),
|
||||
'format' => 'as')),
|
||||
// TRANS: Link for feed with replies for a user.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Replies feed for %s (Activity Streams JSON)'),
|
||||
$this->user->nickname)),
|
||||
$this->target->getNickname())),
|
||||
new Feed(Feed::RSS1,
|
||||
common_local_url('repliesrss',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
array('nickname' => $this->target->getNickname())),
|
||||
// TRANS: Link for feed with replies for a user.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Replies feed for %s (RSS 1.0)'),
|
||||
$this->user->nickname)),
|
||||
$this->target->getNickname())),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('ApiTimelineMentions',
|
||||
array(
|
||||
'id' => $this->user->nickname,
|
||||
'id' => $this->target->getNickname(),
|
||||
'format' => 'rss')),
|
||||
// TRANS: Link for feed with replies for a user.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Replies feed for %s (RSS 2.0)'),
|
||||
$this->user->nickname)),
|
||||
$this->target->getNickname())),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('ApiTimelineMentions',
|
||||
array(
|
||||
'id' => $this->user->nickname,
|
||||
'id' => $this->target->getNickname(),
|
||||
'format' => 'atom')),
|
||||
// TRANS: Link for feed with replies for a user.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Replies feed for %s (Atom)'),
|
||||
$this->user->nickname)));
|
||||
$this->target->getNickname())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the content
|
||||
*
|
||||
* A list of notices that are replies to the user, plus pagination.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
$nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
|
||||
@@ -195,33 +121,30 @@ class RepliesAction extends Action
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'replies',
|
||||
array('nickname' => $this->user->nickname));
|
||||
array('nickname' => $this->target->getNickname()));
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
// TRANS: Empty list message for page with replies for a user.
|
||||
// TRANS: %1$s and %s$s are the user nickname.
|
||||
$message = sprintf(_('This is the timeline showing replies to %1$s but %2$s hasn\'t received a notice to them yet.'),
|
||||
$this->user->nickname,
|
||||
$this->user->nickname) . ' ';
|
||||
// TRANS: %1$s is the user nickname.
|
||||
$message = sprintf(_('This is the timeline showing replies to %1$s but no notices have arrived yet.'), $this->target->getNickname());
|
||||
$message .= ' '; // Spacing between this sentence and the next.
|
||||
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
if ($this->target->getID() === $this->scoped->getID()) {
|
||||
// TRANS: Empty list message for page with replies for a user for the logged in user.
|
||||
// TRANS: This message contains a Markdown link in the form [link text](link).
|
||||
$message .= _('You can engage other users in a conversation, subscribe to more people or [join groups](%%action.groups%%).');
|
||||
} else {
|
||||
// TRANS: Empty list message for page with replies for a user for all logged in users but the user themselves.
|
||||
// TRANS: %1$s, %2$s and %3$s are a user nickname. This message contains a Markdown link in the form [link text](link).
|
||||
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
|
||||
// TRANS: %1$s is a user nickname and %2$s is the same but with a prepended '@' character. This message contains a Markdown link in the form [link text](link).
|
||||
$message .= sprintf(_('You can try to [nudge %1$s](../%1$s) or [post something to them](%%%%action.newnotice%%%%?content=%2$s).'), $this->target->getNickname(), '@' . $this->target->getNickname());
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// TRANS: Empty list message for page with replies for a user for not logged in users.
|
||||
// TRANS: %1$s is a user nickname. This message contains a Markdown link in the form [link text](link).
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->user->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');
|
||||
@@ -229,7 +152,7 @@ class RepliesAction extends Action
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
public function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,70 +17,34 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once(INSTALLDIR.'/lib/rssaction.php');
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
// Formatting of RSS handled by Rss10Action
|
||||
|
||||
class RepliesrssAction extends Rss10Action
|
||||
class RepliesrssAction extends TargetedRss10Action
|
||||
{
|
||||
var $user = null;
|
||||
|
||||
function prepare($args)
|
||||
protected function getNotices()
|
||||
{
|
||||
parent::prepare($args);
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$this->user = User::getKV('nickname', $nickname);
|
||||
|
||||
if (!$this->user) {
|
||||
// TRANS: Client error displayed when providing a non-existing nickname in a RSS 1.0 action.
|
||||
$this->clientError(_('No such user.'));
|
||||
} else {
|
||||
$this->notices = $this->getNotices($this->limit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function getNotices($limit=0)
|
||||
{
|
||||
$user = $this->user;
|
||||
|
||||
$notice = $user->getReplies(0, ($limit == 0) ? 48 : $limit);
|
||||
|
||||
$notices = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
$stream = $this->target->getReplies(0, $this->limit);
|
||||
return $stream->fetchAll();
|
||||
}
|
||||
|
||||
function getChannel()
|
||||
{
|
||||
$user = $this->user;
|
||||
$c = array('url' => common_local_url('repliesrss',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
$this->target->getNickname())),
|
||||
// TRANS: RSS reply feed title. %s is a user nickname.
|
||||
'title' => sprintf(_("Replies to %s"), $user->nickname),
|
||||
'title' => sprintf(_("Replies to %s"), $this->target->getNickname()),
|
||||
'link' => common_local_url('replies',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
array('nickname' => $this->target->getNickname())),
|
||||
// TRANS: RSS reply feed description.
|
||||
// TRANS: %1$s is a user nickname, %2$s is the StatusNet site name.
|
||||
'description' => sprintf(_('Replies to %1$s on %2$s.'),
|
||||
$user->nickname, common_config('site', 'name')));
|
||||
$this->target->getNickname(), common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
function getImage()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
return $profile->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
|
||||
+3
-15
@@ -27,9 +27,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Prints out a static robots.txt
|
||||
@@ -40,19 +38,9 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class RobotstxtAction extends Action
|
||||
class RobotstxtAction extends ManagedAction
|
||||
{
|
||||
/**
|
||||
* Handles requests
|
||||
*
|
||||
* Since this is a relatively static document, we
|
||||
* don't do a prepare()
|
||||
*
|
||||
* @param array $args GET, POST, and URL params; unused.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
public function showPage()
|
||||
{
|
||||
if (Event::handle('StartRobotsTxt', array($this))) {
|
||||
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@ class RsdAction extends Action
|
||||
$this->elementStart('api', $apiAttrs);
|
||||
$this->elementStart('settings');
|
||||
$this->element('docs', null,
|
||||
'http://status.net/wiki/TwitterCompatibleAPI');
|
||||
common_local_url('doc', array('title' => 'api')));
|
||||
$this->element('setting', array('name' => 'OAuth'),
|
||||
'true');
|
||||
$this->elementEnd('settings');
|
||||
|
||||
+33
-31
@@ -70,10 +70,11 @@ class ShownoticeAction extends ManagedAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
if ($this->boolean('ajax')) {
|
||||
StatusNet::setApi(true);
|
||||
GNUsocial::setApi(true);
|
||||
}
|
||||
|
||||
$this->notice = $this->getNotice();
|
||||
$this->target = $this->notice;
|
||||
|
||||
if (!$this->notice->inScope($this->scoped)) {
|
||||
// TRANS: Client exception thrown when trying a view a notice the user has no access to.
|
||||
@@ -113,20 +114,22 @@ class ShownoticeAction extends ManagedAction
|
||||
{
|
||||
$id = $this->arg('notice');
|
||||
|
||||
$notice = Notice::getKV('id', $id);
|
||||
if ($notice instanceof Notice) {
|
||||
$notice = null;
|
||||
try {
|
||||
$notice = Notice::getByID($id);
|
||||
// Alright, got it!
|
||||
return $notice;
|
||||
}
|
||||
|
||||
// Did we use to have it, and it got deleted?
|
||||
$deleted = Deleted_notice::getKV('id', $id);
|
||||
if ($deleted instanceof Deleted_notice) {
|
||||
// TRANS: Client error displayed trying to show a deleted notice.
|
||||
$this->clientError(_('Notice deleted.'), 410);
|
||||
} catch (NoResultException $e) {
|
||||
// Hm, not found.
|
||||
$deleted = null;
|
||||
Event::handle('IsNoticeDeleted', array($id, &$deleted));
|
||||
if ($deleted === true) {
|
||||
// TRANS: Client error displayed trying to show a deleted notice.
|
||||
throw new ClientException(_('Notice deleted.'), 410);
|
||||
}
|
||||
}
|
||||
// TRANS: Client error displayed trying to show a non-existing notice.
|
||||
$this->clientError(_('No such notice.'), 404);
|
||||
throw new ClientException(_('No such notice.'), 404);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,36 +214,35 @@ class ShownoticeAction extends ManagedAction
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show aside
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showAside() {
|
||||
function getFeeds()
|
||||
{
|
||||
return array(new Feed(Feed::JSON,
|
||||
common_local_url('ApiStatusesShow',
|
||||
array(
|
||||
'id' => $this->target->getID(),
|
||||
'format' => 'json')),
|
||||
// TRANS: Title for link to single notice representation.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Single notice (JSON)'))),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('ApiStatusesShow',
|
||||
array(
|
||||
'id' => $this->target->getID(),
|
||||
'format' => 'atom')),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Single notice (Atom)'))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra <head> content
|
||||
*
|
||||
* We show the microid(s) for the author, if any.
|
||||
* Facebook OpenGraph metadata.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function extraHead()
|
||||
{
|
||||
$user = User::getKV($this->profile->id);
|
||||
|
||||
if (!$user instanceof User) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user->emailmicroid && $user->email && $this->notice->uri) {
|
||||
$id = new Microid('mailto:'. $user->email,
|
||||
$this->notice->uri);
|
||||
$this->element('meta', array('name' => 'microid',
|
||||
'content' => $id->toString()));
|
||||
}
|
||||
|
||||
// Extras to aid in sharing notices to Facebook
|
||||
$avatarUrl = $this->profile->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$this->element('meta', array('property' => 'og:image',
|
||||
|
||||
+29
-119
@@ -22,97 +22,31 @@
|
||||
* @link http://status.net
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
require_once INSTALLDIR.'/lib/profileminilist.php';
|
||||
require_once INSTALLDIR.'/lib/peopletaglist.php';
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
|
||||
class ShowprofiletagAction extends Action
|
||||
class ShowprofiletagAction extends ShowstreamAction
|
||||
{
|
||||
var $notice, $tagger, $peopletag, $userProfile;
|
||||
var $notice, $peopletag;
|
||||
|
||||
function isReadOnly($args)
|
||||
protected function doStreamPreparation()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (common_config('singleuser', 'enabled')) {
|
||||
$tagger_arg = User::singleUserNickname();
|
||||
} else {
|
||||
$tagger_arg = $this->arg('tagger');
|
||||
}
|
||||
$tag_arg = $this->arg('tag');
|
||||
$tagger = common_canonical_nickname($tagger_arg);
|
||||
$tag = common_canonical_tag($tag_arg);
|
||||
|
||||
// Permanent redirect on non-canonical nickname
|
||||
|
||||
if ($tagger_arg != $tagger || $tag_arg != $tag) {
|
||||
$args = array('tagger' => $nickname, 'tag' => $tag);
|
||||
if ($this->page != 1) {
|
||||
$args['page'] = $this->page;
|
||||
}
|
||||
common_redirect(common_local_url('showprofiletag', $args), 301);
|
||||
}
|
||||
|
||||
if (!$tagger) {
|
||||
// TRANS: Client error displayed when a tagger is expected but not provided.
|
||||
$this->clientError(_('No tagger.'), 404);
|
||||
}
|
||||
|
||||
$user = User::getKV('nickname', $tagger);
|
||||
|
||||
if (!$user) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->tagger = $user->getProfile();
|
||||
$this->peopletag = Profile_list::pkeyGet(array('tagger' => $user->id, 'tag' => $tag));
|
||||
|
||||
$current = common_current_user();
|
||||
$can_see = !empty($this->peopletag) && (!$this->peopletag->private ||
|
||||
($this->peopletag->private && $this->peopletag->tagger === $current->id));
|
||||
|
||||
if (!$can_see) {
|
||||
$tag = common_canonical_tag($this->arg('tag'));
|
||||
try {
|
||||
$this->peopletag = Profile_list::getByPK(array('tagger' => $this->target->getID(), 'tag' => $tag));
|
||||
} catch (NoResultException $e) {
|
||||
// TRANS: Client error displayed trying to reference a non-existing list.
|
||||
$this->clientError(_('No such list.'), 404);
|
||||
throw new ClientException('No such list.');
|
||||
}
|
||||
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||
$this->userProfile = Profile::current();
|
||||
|
||||
$stream = new PeopletagNoticeStream($this->peopletag, $this->userProfile);
|
||||
|
||||
$this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
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);
|
||||
if ($this->peopletag->private && !$this->peopletag->getTagger()->sameAs($this->scoped)) {
|
||||
// TRANS: Client error displayed trying to reference a non-existing list.
|
||||
throw new AuthorizationException('You do not have permission to see this list.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
public function getStream()
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!$this->peopletag) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'));
|
||||
}
|
||||
|
||||
$this->showPage();
|
||||
return new PeopletagNoticeStream($this->peopletag, $this->scoped);
|
||||
}
|
||||
|
||||
function title()
|
||||
@@ -137,7 +71,7 @@ class ShowprofiletagAction extends Action
|
||||
// TRANS: %1$s is a list, %2$s is the tagger's nickname, %3$d is a page number.
|
||||
return sprintf(_('Timeline for %1$s list by %2$s, page %3$d'),
|
||||
$this->peopletag->tag,
|
||||
$this->tagger->nickname,
|
||||
$this->target->getNickname(),
|
||||
$this->page
|
||||
);
|
||||
} else {
|
||||
@@ -160,7 +94,7 @@ class ShowprofiletagAction extends Action
|
||||
// TRANS: %1$s is a list, %2$s is the tagger's nickname.
|
||||
return sprintf(_('Timeline for %1$s list by %2$s'),
|
||||
$this->peopletag->tag,
|
||||
$this->tagger->nickname
|
||||
$this->target->getNickname()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -171,29 +105,29 @@ class ShowprofiletagAction extends Action
|
||||
return array(new Feed(Feed::JSON,
|
||||
common_local_url(
|
||||
'ApiTimelineList', array(
|
||||
'user' => $this->tagger->id,
|
||||
'user' => $this->target->id,
|
||||
'id' => $this->peopletag->id,
|
||||
'format' => 'as'
|
||||
)
|
||||
),
|
||||
// TRANS: Feed title.
|
||||
// TRANS: %s is tagger's nickname.
|
||||
sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->tagger->nickname)),
|
||||
sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->getNickname())),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url(
|
||||
'ApiTimelineList', array(
|
||||
'user' => $this->tagger->id,
|
||||
'user' => $this->target->id,
|
||||
'id' => $this->peopletag->id,
|
||||
'format' => 'rss'
|
||||
)
|
||||
),
|
||||
// TRANS: Feed title.
|
||||
// TRANS: %s is tagger's nickname.
|
||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->tagger->nickname)),
|
||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->getNickname())),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url(
|
||||
'ApiTimelineList', array(
|
||||
'user' => $this->tagger->id,
|
||||
'user' => $this->target->id,
|
||||
'id' => $this->peopletag->id,
|
||||
'format' => 'atom'
|
||||
)
|
||||
@@ -201,7 +135,7 @@ class ShowprofiletagAction extends Action
|
||||
// TRANS: Feed title.
|
||||
// TRANS: %1$s is a list, %2$s is tagger's nickname.
|
||||
sprintf(_('Feed for %1$s list by %2$s (Atom)'),
|
||||
$this->peopletag->tag, $this->tagger->nickname
|
||||
$this->peopletag->tag, $this->target->getNickname()
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -219,11 +153,10 @@ class ShowprofiletagAction extends Action
|
||||
// TRANS: %1$s is a list, %2$s is a tagger's nickname.
|
||||
$message = sprintf(_('This is the timeline for %1$s list by %2$s but no one has posted anything yet.'),
|
||||
$this->peopletag->tag,
|
||||
$this->tagger->nickname) . ' ';
|
||||
$this->target->getNickname()) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->tagger->id == $current_user->id) {
|
||||
if ($this->target->sameAs($this->scoped)) {
|
||||
// TRANS: Additional empty list message for list timeline for currently logged in user tagged tags.
|
||||
$message .= _('Try tagging more people.');
|
||||
}
|
||||
@@ -238,16 +171,15 @@ class ShowprofiletagAction extends Action
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showContent()
|
||||
protected function showContent()
|
||||
{
|
||||
$this->showPeopletag();
|
||||
$this->showNotices();
|
||||
parent::showContent();
|
||||
}
|
||||
|
||||
function showPeopletag()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
$tag = new Peopletag($this->peopletag, $cur, $this);
|
||||
$tag = new Peopletag($this->peopletag, $this->scoped, $this);
|
||||
$tag->show();
|
||||
}
|
||||
|
||||
@@ -267,7 +199,7 @@ class ShowprofiletagAction extends Action
|
||||
$this->page,
|
||||
'showprofiletag',
|
||||
array('tag' => $this->peopletag->tag,
|
||||
'tagger' => $this->tagger->nickname)
|
||||
'nickname' => $this->target->getNickname())
|
||||
);
|
||||
|
||||
Event::handle('EndShowProfileTagContent', array($this));
|
||||
@@ -283,11 +215,6 @@ class ShowprofiletagAction extends Action
|
||||
# $this->showStatistics();
|
||||
}
|
||||
|
||||
function showPageTitle()
|
||||
{
|
||||
$this->element('h1', null, $this->title());
|
||||
}
|
||||
|
||||
function showTagged()
|
||||
{
|
||||
$profile = $this->peopletag->getTagged(0, PROFILES_PER_MINILIST + 1);
|
||||
@@ -314,7 +241,7 @@ class ShowprofiletagAction extends Action
|
||||
if ($cnt > PROFILES_PER_MINILIST) {
|
||||
$this->elementStart('p');
|
||||
$this->element('a', array('href' => common_local_url('taggedprofiles',
|
||||
array('nickname' => $this->tagger->nickname,
|
||||
array('nickname' => $this->target->getNickname(),
|
||||
'profiletag' => $this->peopletag->tag)),
|
||||
'class' => 'more'),
|
||||
// TRANS: Link for more "People in list x by a user"
|
||||
@@ -356,20 +283,3 @@ class ShowprofiletagAction extends Action
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
|
||||
class Peopletag extends PeopletagListItem
|
||||
{
|
||||
protected $avatarSize = AVATAR_PROFILE_SIZE;
|
||||
|
||||
function showStart()
|
||||
{
|
||||
$mode = $this->peopletag->private ? 'private' : 'public';
|
||||
$this->out->elementStart('div', array('class' => 'h-entry peopletag peopletag-profile mode-'.$mode,
|
||||
'id' => 'peopletag-' . $this->peopletag->id));
|
||||
}
|
||||
|
||||
function showEnd()
|
||||
{
|
||||
$this->out->elementEnd('div');
|
||||
}
|
||||
}
|
||||
|
||||
+39
-120
@@ -28,15 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
require_once INSTALLDIR.'/lib/profileminilist.php';
|
||||
require_once INSTALLDIR.'/lib/groupminilist.php';
|
||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* User profile page
|
||||
@@ -53,29 +45,22 @@ 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
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ShowstreamAction extends ProfileAction
|
||||
class ShowstreamAction extends NoticestreamAction
|
||||
{
|
||||
var $notice;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
public function getStream()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (empty($this->tag)) {
|
||||
$stream = new ProfileNoticeStream($this->profile, $this->scoped);
|
||||
$stream = new ProfileNoticeStream($this->target, $this->scoped);
|
||||
} else {
|
||||
$stream = new TaggedProfileNoticeStream($this->profile, $this->tag, $this->scoped);
|
||||
$stream = new TaggedProfileNoticeStream($this->target, $this->tag, $this->scoped);
|
||||
}
|
||||
|
||||
$this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||
|
||||
return true;
|
||||
return $stream;
|
||||
}
|
||||
|
||||
|
||||
function title()
|
||||
{
|
||||
$base = $this->profile->getFancyName();
|
||||
$base = $this->target->getFancyName();
|
||||
if (!empty($this->tag)) {
|
||||
if ($this->page == 1) {
|
||||
// TRANS: Page title showing tagged notices in one user's timeline.
|
||||
@@ -88,7 +73,7 @@ class ShowstreamAction extends ProfileAction
|
||||
}
|
||||
} else {
|
||||
if ($this->page == 1) {
|
||||
return $base;
|
||||
return sprintf(_('Notices by %s'), $base);
|
||||
} else {
|
||||
// TRANS: Extended page title showing tagged notices in one user's timeline.
|
||||
// TRANS: %1$s is the username, %2$d is the page number.
|
||||
@@ -99,14 +84,14 @@ class ShowstreamAction extends ProfileAction
|
||||
}
|
||||
}
|
||||
|
||||
function showContent()
|
||||
protected function showContent()
|
||||
{
|
||||
$this->showNotices();
|
||||
}
|
||||
|
||||
function showProfileBlock()
|
||||
{
|
||||
$block = new AccountProfileBlock($this, $this->profile);
|
||||
$block = new AccountProfileBlock($this, $this->target);
|
||||
$block->show();
|
||||
}
|
||||
|
||||
@@ -120,78 +105,71 @@ class ShowstreamAction extends ProfileAction
|
||||
if (!empty($this->tag)) {
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('userrss',
|
||||
array('nickname' => $this->target->nickname,
|
||||
array('nickname' => $this->target->getNickname(),
|
||||
'tag' => $this->tag)),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %1$s is a user nickname, %2$s is a hashtag.
|
||||
sprintf(_('Notice feed for %1$s tagged %2$s (RSS 1.0)'),
|
||||
$this->target->nickname, $this->tag)));
|
||||
$this->target->getNickname(), $this->tag)));
|
||||
}
|
||||
|
||||
return array(new Feed(Feed::JSON,
|
||||
common_local_url('ApiTimelineUser',
|
||||
array(
|
||||
'id' => $this->user->id,
|
||||
'id' => $this->target->getID(),
|
||||
'format' => 'as')),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Notice feed for %s (Activity Streams JSON)'),
|
||||
$this->target->nickname)),
|
||||
$this->target->getNickname())),
|
||||
new Feed(Feed::RSS1,
|
||||
common_local_url('userrss',
|
||||
array('nickname' => $this->target->nickname)),
|
||||
array('nickname' => $this->target->getNickname())),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Notice feed for %s (RSS 1.0)'),
|
||||
$this->target->nickname)),
|
||||
$this->target->getNickname())),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('ApiTimelineUser',
|
||||
array(
|
||||
'id' => $this->user->id,
|
||||
'id' => $this->target->getID(),
|
||||
'format' => 'rss')),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Notice feed for %s (RSS 2.0)'),
|
||||
$this->target->nickname)),
|
||||
$this->target->getNickname())),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('ApiTimelineUser',
|
||||
array(
|
||||
'id' => $this->user->id,
|
||||
'id' => $this->target->getID(),
|
||||
'format' => 'atom')),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Notice feed for %s (Atom)'),
|
||||
$this->target->nickname)),
|
||||
$this->target->getNickname())),
|
||||
new Feed(Feed::FOAF,
|
||||
common_local_url('foaf', array('nickname' =>
|
||||
$this->target->nickname)),
|
||||
$this->target->getNickname())),
|
||||
// TRANS: Title for link to notice feed. FOAF stands for Friend of a Friend.
|
||||
// TRANS: More information at http://www.foaf-project.org. %s is a user nickname.
|
||||
sprintf(_('FOAF for %s'), $this->target->nickname)));
|
||||
sprintf(_('FOAF for %s'), $this->target->getNickname())));
|
||||
}
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
if ($this->profile->bio) {
|
||||
if ($this->target->bio) {
|
||||
$this->element('meta', array('name' => 'description',
|
||||
'content' => $this->profile->bio));
|
||||
}
|
||||
|
||||
if ($this->user->emailmicroid && $this->user->email && $this->profile->profileurl) {
|
||||
$id = new Microid('mailto:'.$this->user->email,
|
||||
$this->selfUrl());
|
||||
$this->element('meta', array('name' => 'microid',
|
||||
'content' => $id->toString()));
|
||||
'content' => $this->target->getDescription()));
|
||||
}
|
||||
|
||||
// See https://wiki.mozilla.org/Microsummaries
|
||||
|
||||
$this->element('link', array('rel' => 'microsummary',
|
||||
'href' => common_local_url('microsummary',
|
||||
array('nickname' => $this->profile->nickname))));
|
||||
array('nickname' => $this->target->getNickname()))));
|
||||
|
||||
$rsd = common_local_url('rsd',
|
||||
array('nickname' => $this->profile->nickname));
|
||||
array('nickname' => $this->target->getNickname()));
|
||||
|
||||
// RSD, http://tales.phrasewise.com/rfc/rsd
|
||||
$this->element('link', array('rel' => 'EditURI',
|
||||
@@ -200,30 +178,29 @@ class ShowstreamAction extends ProfileAction
|
||||
|
||||
if ($this->page != 1) {
|
||||
$this->element('link', array('rel' => 'canonical',
|
||||
'href' => $this->profile->profileurl));
|
||||
'href' => $this->target->getUrl()));
|
||||
}
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
// TRANS: First sentence of empty list message for a timeline. $1%s is a user nickname.
|
||||
$message = sprintf(_('This is the timeline for %1$s, but %1$s hasn\'t posted anything yet.'), $this->target->nickname) . ' ';
|
||||
$message = sprintf(_('This is the timeline for %1$s, but %1$s hasn\'t posted anything yet.'), $this->target->getNickname()) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
if ($this->scoped instanceof Profile) {
|
||||
if ($this->target->getID() === $this->scoped->getID()) {
|
||||
// TRANS: Second sentence of empty list message for a stream for the user themselves.
|
||||
$message .= _('Seen anything interesting recently? You haven\'t posted any notices yet, now would be a good time to start :)');
|
||||
} else {
|
||||
// TRANS: Second sentence of empty list message for a non-self timeline. %1$s is a user nickname, %2$s is a part of a URL.
|
||||
// TRANS: This message contains a Markdown link. Keep "](" together.
|
||||
$message .= sprintf(_('You can try to nudge %1$s or [post something to them](%%%%action.newnotice%%%%?status_textarea=%2$s).'), $this->target->nickname, '@' . $this->target->nickname);
|
||||
$message .= sprintf(_('You can try to nudge %1$s or [post something to them](%%%%action.newnotice%%%%?status_textarea=%2$s).'), $this->target->getNickname(), '@' . $this->target->getNickname());
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TRANS: Second sentence of empty message for anonymous users. %s is a user nickname.
|
||||
// TRANS: This message contains a Markdown link. 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');
|
||||
@@ -233,16 +210,13 @@ class ShowstreamAction extends ProfileAction
|
||||
|
||||
function showNotices()
|
||||
{
|
||||
$pnl = null;
|
||||
if (Event::handle('ShowStreamNoticeList', array($this->notice, $this, &$pnl))) {
|
||||
$pnl = new ProfileNoticeList($this->notice, $this);
|
||||
}
|
||||
$pnl = new NoticeList($this->notice, $this);
|
||||
$cnt = $pnl->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$args = array('nickname' => $this->target->nickname);
|
||||
$args = array('nickname' => $this->target->getNickname());
|
||||
if (!empty($this->tag))
|
||||
{
|
||||
$args['tag'] = $this->tag;
|
||||
@@ -259,13 +233,13 @@ class ShowstreamAction extends ProfileAction
|
||||
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [StatusNet](http://status.net/) tool. ' .
|
||||
'[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
|
||||
$this->target->nickname, $this->target->nickname);
|
||||
$this->target->getNickname(), $this->target->getNickname());
|
||||
} else {
|
||||
// TRANS: Announcement for anonymous users showing a timeline if site registrations are closed or invite only.
|
||||
// TRANS: This message contains a Markdown link. Keep "](" together.
|
||||
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [StatusNet](http://status.net/) tool.'),
|
||||
$this->target->nickname, $this->target->nickname);
|
||||
$this->target->getNickname(), $this->target->getNickname());
|
||||
}
|
||||
$this->elementStart('div', array('id' => 'anon_notice'));
|
||||
$this->raw(common_markup_to_html($m));
|
||||
@@ -276,7 +250,7 @@ class ShowstreamAction extends ProfileAction
|
||||
{
|
||||
parent::showSections();
|
||||
if (!common_config('performance', 'high')) {
|
||||
$cloud = new PersonalTagCloudSection($this, $this->user);
|
||||
$cloud = new PersonalTagCloudSection($this->target, $this);
|
||||
$cloud->show();
|
||||
}
|
||||
}
|
||||
@@ -284,66 +258,11 @@ class ShowstreamAction extends ProfileAction
|
||||
function noticeFormOptions()
|
||||
{
|
||||
$options = parent::noticeFormOptions();
|
||||
$cur = common_current_user();
|
||||
|
||||
if (empty($cur) || $cur->id != $this->profile->id) {
|
||||
$options['to_profile'] = $this->profile;
|
||||
if (!$this->scoped instanceof Profile || !$this->scoped->sameAs($this->target)) {
|
||||
$options['to_profile'] = $this->target;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't show the author for a profile, since we already know who it is!
|
||||
|
||||
/**
|
||||
* Slightly modified from standard list; the author & avatar are hidden
|
||||
* in CSS. We used to remove them here too, but as it turns out that
|
||||
* confuses the inline reply code... and we hide them in CSS anyway
|
||||
* since realtime updates come through in original form.
|
||||
*
|
||||
* Remaining customization right now is for the repeat marker, where
|
||||
* it'll list who the original poster was instead of who did the repeat
|
||||
* (since the repeater is you, and the repeatee isn't shown!)
|
||||
* This will remain inconsistent if realtime updates come through,
|
||||
* since those'll get rendered as a regular NoticeListItem.
|
||||
*/
|
||||
class ProfileNoticeList extends NoticeList
|
||||
{
|
||||
function newListItem($notice)
|
||||
{
|
||||
return new ProfileNoticeListItem($notice, $this->out);
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileNoticeListItem extends DoFollowListItem
|
||||
{
|
||||
/**
|
||||
* show a link to the author of repeat
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRepeat()
|
||||
{
|
||||
if (!empty($this->repeat)) {
|
||||
|
||||
// FIXME: this code is almost identical to default; need to refactor
|
||||
|
||||
$attrs = array('href' => $this->profile->profileurl,
|
||||
'class' => 'url');
|
||||
|
||||
if (!empty($this->profile->fullname)) {
|
||||
$attrs['title'] = $this->profile->getFancyName();
|
||||
}
|
||||
|
||||
$this->out->elementStart('span', 'repeat');
|
||||
|
||||
$text_link = XMLStringer::estring('a', $attrs, $this->profile->nickname);
|
||||
|
||||
// TRANS: Link to the author of a repeated notice. %s is a linked nickname.
|
||||
$this->out->raw(sprintf(_('Repeat of %s'), $text_link));
|
||||
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-41
@@ -27,9 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Silence a user.
|
||||
@@ -42,45 +40,11 @@ if (!defined('STATUSNET')) {
|
||||
*/
|
||||
class SilenceAction extends ProfileFormAction
|
||||
{
|
||||
/**
|
||||
* Check parameters
|
||||
*
|
||||
* @param array $args action arguments (URL, GET, POST)
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
if (!parent::prepare($args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
assert(!empty($cur)); // checked by parent
|
||||
|
||||
if (!$cur->hasRight(Right::SILENCEUSER)) {
|
||||
// TRANS: Client error displayed trying to silence a user on a site where the feature is not enabled.
|
||||
$this->clientError(_('You cannot silence users on this site.'));
|
||||
}
|
||||
|
||||
assert(!empty($this->profile)); // checked by parent
|
||||
|
||||
if ($this->profile->isSilenced()) {
|
||||
// TRANS: Client error displayed trying to silence an already silenced user.
|
||||
$this->clientError(_('User is already silenced.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Silence a user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
{
|
||||
$this->profile->silence();
|
||||
assert($this->scoped instanceof Profile);
|
||||
assert($this->profile instanceof Profile);
|
||||
|
||||
$this->profile->silenceAs($this->scoped);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Update the site-wide notice text
|
||||
@@ -114,13 +110,9 @@ class SitenoticeadminpanelAction extends AdminPanelAction
|
||||
}
|
||||
|
||||
// scrub HTML input
|
||||
|
||||
$config = array(
|
||||
'safe' => 1,
|
||||
'deny_attribute' => 'id,style,on*'
|
||||
);
|
||||
|
||||
$siteNotice = htmLawed($siteNotice, $config);
|
||||
require_once INSTALLDIR.'/extlib/HTMLPurifier/HTMLPurifier.auto.php';
|
||||
$purifier = new HTMLPurifier();
|
||||
$siteNotice = $purifier->purify($siteNotice);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+63
-105
@@ -27,9 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Settings for SMS
|
||||
@@ -45,6 +43,14 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
|
||||
class SmssettingsAction extends SettingsAction
|
||||
{
|
||||
protected function doPreparation()
|
||||
{
|
||||
if (!common_config('sms', 'enabled')) {
|
||||
// TRANS: Message given in the SMS settings if SMS is not enabled on the site.
|
||||
throw new ServerException(_('SMS is not available.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
@@ -86,14 +92,7 @@ class SmssettingsAction extends SettingsAction
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
if (!common_config('sms', 'enabled')) {
|
||||
$this->element('div', array('class' => 'error'),
|
||||
// TRANS: Message given in the SMS settings if SMS is not enabled on the site.
|
||||
_('SMS is not available.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_sms',
|
||||
@@ -118,8 +117,8 @@ class SmssettingsAction extends SettingsAction
|
||||
// TRANS: Button label to remove a confirmed SMS address.
|
||||
$this->submit('remove', _m('BUTTON','Remove'));
|
||||
} else {
|
||||
$confirm = $this->getConfirmation();
|
||||
if ($confirm) {
|
||||
try {
|
||||
$confirm = $this->getConfirmation();
|
||||
$carrier = Sms_carrier::getKV($confirm->address_extra);
|
||||
$this->element('p', 'form_unconfirmed',
|
||||
$confirm->address . ' (' . $carrier->name . ')');
|
||||
@@ -141,7 +140,7 @@ class SmssettingsAction extends SettingsAction
|
||||
$this->elementEnd('ul');
|
||||
// TRANS: Button label to confirm SMS confirmation code in SMS settings.
|
||||
$this->submit('confirm', _m('BUTTON','Confirm'));
|
||||
} else {
|
||||
} catch (NoResultException $e) {
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label for SMS phone number input in SMS settings form.
|
||||
@@ -216,60 +215,38 @@ class SmssettingsAction extends SettingsAction
|
||||
*/
|
||||
function getConfirmation()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$confirm = new Confirm_address();
|
||||
|
||||
$confirm->user_id = $user->id;
|
||||
$confirm->user_id = $this->scoped->getID();
|
||||
$confirm->address_type = 'sms';
|
||||
|
||||
if ($confirm->find(true)) {
|
||||
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
|
||||
* to do the actual task requested.
|
||||
*
|
||||
* All sub-functions reload the form with a message -- success or failure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
// 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')) {
|
||||
$this->savePreferences();
|
||||
return $this->savePreferences();
|
||||
} else if ($this->arg('add')) {
|
||||
$this->addAddress();
|
||||
return $this->addAddress();
|
||||
} else if ($this->arg('cancel')) {
|
||||
$this->cancelConfirmation();
|
||||
return $this->cancelConfirmation();
|
||||
} else if ($this->arg('remove')) {
|
||||
$this->removeAddress();
|
||||
return $this->removeAddress();
|
||||
} else if ($this->arg('removeincoming')) {
|
||||
$this->removeIncoming();
|
||||
return $this->removeIncoming();
|
||||
} else if ($this->arg('newincoming')) {
|
||||
$this->newIncoming();
|
||||
return $this->newIncoming();
|
||||
} else if ($this->arg('confirm')) {
|
||||
$this->confirmCode();
|
||||
} else {
|
||||
// TRANS: Message given submitting a form with an unknown action in SMS settings.
|
||||
$this->showForm(_('Unexpected form submission.'));
|
||||
return $this->confirmCode();
|
||||
}
|
||||
// TRANS: Message given submitting a form with an unknown action in SMS settings.
|
||||
throw new ClientException(_('Unexpected form submission.'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,30 +258,26 @@ class SmssettingsAction extends SettingsAction
|
||||
*/
|
||||
function savePreferences()
|
||||
{
|
||||
$smsnotify = $this->boolean('smsnotify');
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
assert(!is_null($user)); // should already be checked
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$user->query('BEGIN');
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
$user->smsnotify = $smsnotify;
|
||||
$user->smsnotify = $this->boolean('smsnotify');
|
||||
|
||||
$result = $user->update($original);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error thrown on database error updating SMS preferences.
|
||||
$this->serverError(_('Could not update user.'));
|
||||
throw new ServerException(_('Could not update user.'));
|
||||
}
|
||||
|
||||
$user->query('COMMIT');
|
||||
|
||||
// TRANS: Confirmation message for successful SMS preferences save.
|
||||
$this->showForm(_('SMS preferences saved.'), true);
|
||||
return _('SMS preferences saved.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,28 +297,24 @@ class SmssettingsAction extends SettingsAction
|
||||
|
||||
// Some validation
|
||||
|
||||
if (!$sms) {
|
||||
if (empty($sms)) {
|
||||
// TRANS: Message given saving SMS phone number without having provided one.
|
||||
$this->showForm(_('No phone number.'));
|
||||
return;
|
||||
throw new ClientException(_('No phone number.'));
|
||||
}
|
||||
|
||||
if (!$carrier_id) {
|
||||
if (empty($carrier_id)) {
|
||||
// TRANS: Message given saving SMS phone number without having selected a carrier.
|
||||
$this->showForm(_('No carrier selected.'));
|
||||
return;
|
||||
throw new ClientException(_('No carrier selected.'));
|
||||
}
|
||||
|
||||
$sms = common_canonical_sms($sms);
|
||||
|
||||
if ($user->sms == $sms) {
|
||||
if ($user->sms === $sms) {
|
||||
// TRANS: Message given saving SMS phone number that is already set.
|
||||
$this->showForm(_('That is already your phone number.'));
|
||||
return;
|
||||
throw new AlreadyFulfilledException(_('That is already your phone number.'));
|
||||
} else if ($this->smsExists($sms)) {
|
||||
// TRANS: Message given saving SMS phone number that is already set for another user.
|
||||
$this->showForm(_('That phone number already belongs to another user.'));
|
||||
return;
|
||||
throw new ClientException(_('That phone number already belongs to another user.'));
|
||||
}
|
||||
|
||||
$confirm = new Confirm_address();
|
||||
@@ -353,7 +322,7 @@ class SmssettingsAction extends SettingsAction
|
||||
$confirm->address = $sms;
|
||||
$confirm->address_extra = $carrier_id;
|
||||
$confirm->address_type = 'sms';
|
||||
$confirm->user_id = $user->id;
|
||||
$confirm->user_id = $this->scoped->getID();
|
||||
$confirm->code = common_confirmation_code(40);
|
||||
|
||||
$result = $confirm->insert();
|
||||
@@ -371,11 +340,9 @@ class SmssettingsAction extends SettingsAction
|
||||
$carrier->toEmailAddress($sms));
|
||||
|
||||
// TRANS: Message given saving valid SMS phone number that is to be confirmed.
|
||||
$msg = _('A confirmation code was sent to the phone number you added. '.
|
||||
return _('A confirmation code was sent to the phone number you added. '.
|
||||
'Check your phone for the code and instructions '.
|
||||
'on how to use it.');
|
||||
|
||||
$this->showForm($msg, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,29 +357,27 @@ class SmssettingsAction extends SettingsAction
|
||||
$sms = $this->trimmed('sms');
|
||||
$carrier = $this->trimmed('carrier');
|
||||
|
||||
$confirm = $this->getConfirmation();
|
||||
|
||||
if (!$confirm) {
|
||||
try {
|
||||
$confirm = $this->getConfirmation();
|
||||
if ($confirm->address != $sms) {
|
||||
// TRANS: Message given canceling SMS phone number confirmation for the wrong phone number.
|
||||
throw new ClientException(_('That is the wrong confirmation number.'));
|
||||
}
|
||||
} catch (NoResultException $e) {
|
||||
// TRANS: Message given canceling SMS phone number confirmation that is not pending.
|
||||
$this->showForm(_('No pending confirmation to cancel.'));
|
||||
return;
|
||||
}
|
||||
if ($confirm->address != $sms) {
|
||||
// TRANS: Message given canceling SMS phone number confirmation for the wrong phone number.
|
||||
$this->showForm(_('That is the wrong confirmation number.'));
|
||||
return;
|
||||
throw new AlreadyFulfilledException(_('No pending confirmation to cancel.'));
|
||||
}
|
||||
|
||||
$result = $confirm->delete();
|
||||
|
||||
if (!$result) {
|
||||
if ($result === false) {
|
||||
common_log_db_error($confirm, 'DELETE', __FILE__);
|
||||
// TRANS: Server error thrown on database error canceling SMS phone number confirmation.
|
||||
$this->serverError(_('Could not delete SMS confirmation.'));
|
||||
throw new ServerException(_('Could not delete SMS confirmation.'));
|
||||
}
|
||||
|
||||
// TRANS: Message given after successfully canceling SMS phone number confirmation.
|
||||
$this->showForm(_('SMS confirmation cancelled.'), true);
|
||||
return _('SMS confirmation cancelled.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -422,7 +387,7 @@ class SmssettingsAction extends SettingsAction
|
||||
*/
|
||||
function removeAddress()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$sms = $this->arg('sms');
|
||||
$carrier = $this->arg('carrier');
|
||||
@@ -432,8 +397,7 @@ class SmssettingsAction extends SettingsAction
|
||||
if ($user->sms != $sms) {
|
||||
// TRANS: Message given trying to remove an SMS phone number that is not
|
||||
// TRANS: registered for the active user.
|
||||
$this->showForm(_('That is not your phone number.'));
|
||||
return;
|
||||
throw new ClientException(_('That is not your phone number.'));
|
||||
}
|
||||
|
||||
$original = clone($user);
|
||||
@@ -446,7 +410,7 @@ class SmssettingsAction extends SettingsAction
|
||||
$user->updateWithKeys($original);
|
||||
|
||||
// TRANS: Message given after successfully removing a registered SMS phone number.
|
||||
$this->showForm(_('The SMS phone number was removed.'), true);
|
||||
return _('The SMS phone number was removed.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,15 +424,13 @@ class SmssettingsAction extends SettingsAction
|
||||
*/
|
||||
function smsExists($sms)
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$other = User::getKV('sms', $sms);
|
||||
|
||||
if (!$other) {
|
||||
if (!$other instanceof User) {
|
||||
return false;
|
||||
} else {
|
||||
return $other->id != $user->id;
|
||||
}
|
||||
|
||||
return !$this->scoped->sameAs($other->getProfile());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -519,15 +481,12 @@ class SmssettingsAction extends SettingsAction
|
||||
{
|
||||
$code = $this->trimmed('code');
|
||||
|
||||
if (!$code) {
|
||||
if (empty($code)) {
|
||||
// TRANS: Message given saving SMS phone number confirmation code without having provided one.
|
||||
$this->showForm(_('No code entered.'));
|
||||
return;
|
||||
throw new ClientException(_('No code entered.'));
|
||||
}
|
||||
|
||||
common_redirect(common_local_url('confirmaddress',
|
||||
array('code' => $code)),
|
||||
303);
|
||||
common_redirect(common_local_url('confirmaddress', array('code' => $code)), 303);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -541,8 +500,7 @@ class SmssettingsAction extends SettingsAction
|
||||
|
||||
if (!$user->incomingemail) {
|
||||
// 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.'));
|
||||
return;
|
||||
throw new ClientException(_('No incoming email address.'));
|
||||
}
|
||||
|
||||
$orig = clone($user);
|
||||
@@ -553,7 +511,7 @@ class SmssettingsAction extends SettingsAction
|
||||
$user->updateWithKeys($orig);
|
||||
|
||||
// TRANS: Confirmation text after updating SMS settings.
|
||||
$this->showForm(_('Incoming email address removed.'), true);
|
||||
return _('Incoming email address removed.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,7 +523,7 @@ class SmssettingsAction extends SettingsAction
|
||||
*/
|
||||
function newIncoming()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$orig = clone($user);
|
||||
|
||||
@@ -575,6 +533,6 @@ class SmssettingsAction extends SettingsAction
|
||||
$user->updateWithKeys($orig);
|
||||
|
||||
// TRANS: Confirmation text after updating SMS settings.
|
||||
$this->showForm(_('New incoming email address added.'), true);
|
||||
return _('New incoming email address added.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Startpage action. Decides what to show on the first page.
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class StartpageAction extends ManagedAction
|
||||
{
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function showPage()
|
||||
{
|
||||
if (common_config('singleuser', 'enabled')) {
|
||||
$user = User::singleUser();
|
||||
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)), 303);
|
||||
} elseif (common_config('public', 'localonly')) {
|
||||
common_redirect(common_local_url('public'), 303);
|
||||
} else {
|
||||
common_redirect(common_local_url('networkpublic'), 303);
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-43
@@ -27,11 +27,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once(INSTALLDIR.'/lib/profilelist.php');
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* List of group members
|
||||
@@ -50,9 +46,9 @@ class SubqueueAction extends GalleryAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->scoped->id != $this->target->id) {
|
||||
if (!$this->target->sameAs($this->scoped)) {
|
||||
// TRANS: Client error displayed when trying to approve group applicants without being a group administrator.
|
||||
$this->clientError(_('You may only approve your own pending subscriptions.'));
|
||||
throw new ClientException(_('You may only approve your own pending subscriptions.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -88,47 +84,21 @@ class SubqueueAction extends GalleryAction
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
$members = $this->target->getRequests($offset, $limit);
|
||||
|
||||
if ($members) {
|
||||
// @fixme change!
|
||||
$member_list = new SubQueueList($members, $this);
|
||||
$cnt = $member_list->show();
|
||||
try {
|
||||
$subqueue = $this->target->getRequests($offset, $limit);
|
||||
} catch (NoResultException $e) {
|
||||
// TRANS: If no pending subscription requests are found
|
||||
$this->element('div', null, _m('You have no pending subscription requests.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$members->free();
|
||||
$list = new SubQueueList($subqueue, $this);
|
||||
$cnt = $list->show();
|
||||
|
||||
$subqueue->free();
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
|
||||
$this->page, 'subqueue',
|
||||
array('nickname' => $this->target->getNickname())); // urgh
|
||||
}
|
||||
}
|
||||
|
||||
class SubQueueList extends ProfileList
|
||||
{
|
||||
function newListItem($profile)
|
||||
{
|
||||
return new SubQueueListItem($profile, $this->action);
|
||||
}
|
||||
}
|
||||
|
||||
class SubQueueListItem extends ProfileListItem
|
||||
{
|
||||
function showActions()
|
||||
{
|
||||
$this->startActions();
|
||||
if (Event::handle('StartProfileListItemActionElements', array($this))) {
|
||||
$this->showApproveButtons();
|
||||
Event::handle('EndProfileListItemActionElements', array($this));
|
||||
}
|
||||
$this->endActions();
|
||||
}
|
||||
|
||||
function showApproveButtons()
|
||||
{
|
||||
$this->out->elementStart('li', 'entity_approval');
|
||||
$form = new ApproveSubForm($this->out, $this->profile);
|
||||
$form->show();
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ class SubscribeAction extends Action
|
||||
{
|
||||
// Throws exception on error
|
||||
|
||||
$sub = Subscription::start($this->user->getProfile(),
|
||||
$sub = Subscription::ensureStart($this->user->getProfile(),
|
||||
$this->other);
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
|
||||
@@ -132,64 +132,3 @@ class SubscribersAction extends GalleryAction
|
||||
parent::showSections();
|
||||
}
|
||||
}
|
||||
|
||||
class SubscribersList extends SubscriptionList
|
||||
{
|
||||
function newListItem($profile)
|
||||
{
|
||||
return new SubscribersListItem($profile, $this->owner, $this->action);
|
||||
}
|
||||
}
|
||||
|
||||
class SubscribersListItem extends SubscriptionListItem
|
||||
{
|
||||
function showActions()
|
||||
{
|
||||
$this->startActions();
|
||||
if (Event::handle('StartProfileListItemActionElements', array($this))) {
|
||||
$this->showSubscribeButton();
|
||||
// Relevant code!
|
||||
$this->showBlockForm();
|
||||
Event::handle('EndProfileListItemActionElements', array($this));
|
||||
}
|
||||
$this->endActions();
|
||||
}
|
||||
|
||||
function showBlockForm()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
if (!empty($user) && $this->owner->id == $user->id) {
|
||||
$returnto = array('action' => 'subscribers',
|
||||
'nickname' => $this->owner->getNickname());
|
||||
$page = $this->out->arg('page');
|
||||
if ($page) {
|
||||
$returnto['param-page'] = $page;
|
||||
}
|
||||
$bf = new BlockForm($this->out, $this->profile, $returnto);
|
||||
$bf->show();
|
||||
}
|
||||
}
|
||||
|
||||
function linkAttributes()
|
||||
{
|
||||
$aAttrs = parent::linkAttributes();
|
||||
|
||||
if (common_config('nofollow', 'subscribers')) {
|
||||
$aAttrs['rel'] .= ' nofollow';
|
||||
}
|
||||
|
||||
return $aAttrs;
|
||||
}
|
||||
|
||||
function homepageAttributes()
|
||||
{
|
||||
$aAttrs = parent::linkAttributes();
|
||||
|
||||
if (common_config('nofollow', 'subscribers')) {
|
||||
$aAttrs['rel'] = 'nofollow';
|
||||
}
|
||||
|
||||
return $aAttrs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* A list of the user's subscriptions
|
||||
@@ -60,7 +58,7 @@ class SubscriptionsAction extends GalleryAction
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if ($this->scoped instanceof Profile && $this->scoped->id === $this->target->id) {
|
||||
if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) {
|
||||
$this->element('p', null,
|
||||
// TRANS: Page notice for page with an overview of all subscriptions
|
||||
// TRANS: of the logged in user's own profile.
|
||||
@@ -156,71 +154,3 @@ class SubscriptionsAction extends GalleryAction
|
||||
$this->target->getNickname())));
|
||||
}
|
||||
}
|
||||
|
||||
// XXX SubscriptionsList and SubscriptionList are dangerously close
|
||||
|
||||
class SubscriptionsList extends SubscriptionList
|
||||
{
|
||||
function newListItem($profile)
|
||||
{
|
||||
return new SubscriptionsListItem($profile, $this->owner, $this->action);
|
||||
}
|
||||
}
|
||||
|
||||
class SubscriptionsListItem extends SubscriptionListItem
|
||||
{
|
||||
function showOwnerControls()
|
||||
{
|
||||
$sub = Subscription::pkeyGet(array('subscriber' => $this->owner->id,
|
||||
'subscribed' => $this->profile->id));
|
||||
if (!$sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transports = array();
|
||||
Event::handle('GetImTransports', array(&$transports));
|
||||
if (!$transports && !common_config('sms', 'enabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out->elementStart('form', array('id' => 'subedit-' . $this->profile->id,
|
||||
'method' => 'post',
|
||||
'class' => 'form_subscription_edit',
|
||||
'action' => common_local_url('subedit')));
|
||||
$this->out->hidden('token', common_session_token());
|
||||
$this->out->hidden('profile', $this->profile->id);
|
||||
if ($transports) {
|
||||
$attrs = array('name' => 'jabber',
|
||||
'type' => 'checkbox',
|
||||
'class' => 'checkbox',
|
||||
'id' => 'jabber-'.$this->profile->id);
|
||||
if ($sub->jabber) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
// TRANS: Checkbox label for enabling IM messages for a profile in a subscriptions list.
|
||||
$this->out->element('label', array('for' => 'jabber-'.$this->profile->id), _m('LABEL','IM'));
|
||||
} else {
|
||||
$this->out->hidden('jabber', $sub->jabber);
|
||||
}
|
||||
if (common_config('sms', 'enabled')) {
|
||||
$attrs = array('name' => 'sms',
|
||||
'type' => 'checkbox',
|
||||
'class' => 'checkbox',
|
||||
'id' => 'sms-'.$this->profile->id);
|
||||
if ($sub->sms) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
// TRANS: Checkbox label for enabling SMS messages for a profile in a subscriptions list.
|
||||
$this->out->element('label', array('for' => 'sms-'.$this->profile->id), _('SMS'));
|
||||
} else {
|
||||
$this->out->hidden('sms', $sub->sms);
|
||||
}
|
||||
// TRANS: Save button for settings for a profile in a subscriptions list.
|
||||
$this->out->submit('save', _m('BUTTON','Save'));
|
||||
$this->out->elementEnd('form');
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -46,7 +46,8 @@ class TagAction extends ManagedAction
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
$this->notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
|
||||
$this->notice = Notice_tag::getStream($this->tag)->getNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1);
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
// TRANS: Client error when page not found (404).
|
||||
|
||||
+25
-51
@@ -19,9 +19,6 @@
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
require_once INSTALLDIR . '/lib/settingsaction.php';
|
||||
require_once INSTALLDIR . '/lib/peopletags.php';
|
||||
|
||||
class TagprofileAction extends FormAction
|
||||
{
|
||||
var $error = null;
|
||||
@@ -29,36 +26,32 @@ class TagprofileAction extends FormAction
|
||||
protected $target = null;
|
||||
protected $form = 'TagProfile';
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
protected function doPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->trimmed('id');
|
||||
if (!$id) {
|
||||
$this->target = null;
|
||||
} else {
|
||||
$uri = $this->trimmed('uri');
|
||||
if (!empty($id)) {
|
||||
$this->target = Profile::getKV('id', $id);
|
||||
|
||||
if (!$this->target instanceof Profile) {
|
||||
// TRANS: Client error displayed when referring to non-existing profile ID.
|
||||
$this->clientError(_('No profile with that ID.'));
|
||||
}
|
||||
} elseif (!empty($uri)) {
|
||||
$this->target = Profile::fromUri($uri);
|
||||
} else {
|
||||
// TRANS: Client error displayed when trying to tag a user but no ID or profile is provided.
|
||||
$this->clientError(_('No profile identifier provided.'));
|
||||
}
|
||||
|
||||
if ($this->target instanceof Profile && !$this->scoped->canTag($this->target)) {
|
||||
if (!$this->scoped->canTag($this->target)) {
|
||||
// TRANS: Client error displayed when trying to tag a user that cannot be tagged.
|
||||
$this->clientError(_('You cannot tag this user.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
$this->formOpts = $this->target;
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
if (Event::handle('StartTagProfileAction', array($this, $this->target))) {
|
||||
parent::handle();
|
||||
Event::handle('EndTagProfileAction', array($this, $this->target));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function title()
|
||||
@@ -72,6 +65,15 @@ class TagprofileAction extends FormAction
|
||||
return sprintf(_m('ADDTOLIST','List %s'), $this->target->getNickname());
|
||||
}
|
||||
|
||||
function showPage()
|
||||
{
|
||||
// Only serve page content if we aren't POSTing via ajax
|
||||
// otherwise, we serve XML content from doPost()
|
||||
if (!$this->isPost() || !$this->boolean('ajax')) {
|
||||
parent::showPage();
|
||||
}
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('div', 'entity_profile h-card');
|
||||
@@ -115,17 +117,8 @@ class TagprofileAction extends FormAction
|
||||
}
|
||||
}
|
||||
|
||||
protected function getForm()
|
||||
protected function doPost()
|
||||
{
|
||||
$class = $this->form.'Form';
|
||||
$form = new $class($this, $this->target);
|
||||
return $form;
|
||||
}
|
||||
|
||||
protected function handlePost()
|
||||
{
|
||||
parent::handlePost(); // Does nothing for now
|
||||
|
||||
$tagstring = $this->trimmed('tags');
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
@@ -144,22 +137,16 @@ class TagprofileAction extends FormAction
|
||||
if (!common_valid_profile_tag($tag)) {
|
||||
// TRANS: Form validation error displayed if a given tag is invalid.
|
||||
// TRANS: %s is the invalid tag.
|
||||
$this->showForm(sprintf(_('Invalid tag: "%s".'), $tag));
|
||||
return;
|
||||
throw new ClientException(sprintf(_('Invalid tag: "%s".'), $tag));
|
||||
}
|
||||
|
||||
$tag_priv[$tag] = $private;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$result = Profile_tag::setTags($this->scoped->id, $this->target->id, $tags, $tag_priv);
|
||||
if (!$result) {
|
||||
throw new Exception('The tags could not be saved.');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->showForm($e->getMessage());
|
||||
return false;
|
||||
$result = Profile_tag::setTags($this->scoped->getID(), $this->target->getID(), $tags, $tag_priv);
|
||||
if (!$result) {
|
||||
throw new ServerException('The tags could not be saved.');
|
||||
}
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
@@ -188,17 +175,4 @@ class TagprofileAction extends FormAction
|
||||
Event::handle('EndSavePeopletags', array($this, $tagstring));
|
||||
}
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if ($this->error) {
|
||||
$this->element('p', 'error', $this->error);
|
||||
} else {
|
||||
$this->elementStart('div', 'instructions');
|
||||
$this->element('p', null,
|
||||
// TRANS: Page notice.
|
||||
_('Use this form to add your subscribers or subscriptions to lists.'));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-23
@@ -17,42 +17,28 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once(INSTALLDIR.'/lib/rssaction.php');
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
// Formatting of RSS handled by Rss10Action
|
||||
|
||||
class TagrssAction extends Rss10Action
|
||||
{
|
||||
var $tag;
|
||||
protected $tag;
|
||||
|
||||
function prepare($args) {
|
||||
parent::prepare($args);
|
||||
protected function doStreamPreparation()
|
||||
{
|
||||
$tag = common_canonical_tag($this->trimmed('tag'));
|
||||
$this->tag = Notice_tag::getKV('tag', $tag);
|
||||
if (!$this->tag) {
|
||||
if (!$this->tag instanceof Notice_tag) {
|
||||
// TRANS: Client error when requesting a tag feed for a non-existing tag.
|
||||
$this->clientError(_('No such tag.'));
|
||||
} else {
|
||||
$this->notices = $this->getNotices($this->limit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function getNotices($limit=0)
|
||||
protected function getNotices()
|
||||
{
|
||||
$tag = $this->tag;
|
||||
|
||||
if (is_null($tag)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$notice = Notice_tag::getStream($tag->tag, 0, ($limit == 0) ? NOTICES_PER_PAGE : $limit);
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
$stream = Notice_tag::getStream($this->tag->tag)->getNotices(0, $this->limit);
|
||||
return $stream->fetchAll();
|
||||
}
|
||||
|
||||
function getChannel()
|
||||
|
||||
+14
-52
@@ -20,67 +20,29 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Top
|
||||
* @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/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* An action to redirect to the top of the site
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
* @copyright 2015 Free Software Foundation, Inc.
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link https://gnu.io/social
|
||||
*/
|
||||
|
||||
class TopAction extends Action
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class TopAction extends ManagedAction
|
||||
{
|
||||
/**
|
||||
* For initializing members of the class.
|
||||
*
|
||||
* @param array $argarray misc. arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function prepare($argarray)
|
||||
{
|
||||
parent::prepare($argarray);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler method
|
||||
*
|
||||
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($argarray=null)
|
||||
public function showPage()
|
||||
{
|
||||
if (common_config('singleuser', 'enabled')) {
|
||||
$url = common_local_url('showstream', array('nickname' => User::singleUserNickname()));
|
||||
$user = User::singleUser();
|
||||
common_redirect(common_local_url('showstream', array('nickname' => $user->getNickname())), 303);
|
||||
} elseif (common_config('public', 'localonly')) {
|
||||
common_redirect(common_local_url('public'), 303);
|
||||
} else {
|
||||
$url = common_local_url('public');
|
||||
common_redirect(common_local_url('networkpublic'), 303);
|
||||
}
|
||||
|
||||
// XXX: Permanent? I think so.
|
||||
|
||||
common_redirect($url, 301);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-42
@@ -27,12 +27,10 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Silence a user.
|
||||
* Unsilence a user.
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
@@ -42,45 +40,11 @@ if (!defined('STATUSNET')) {
|
||||
*/
|
||||
class UnsilenceAction extends ProfileFormAction
|
||||
{
|
||||
/**
|
||||
* Check parameters
|
||||
*
|
||||
* @param array $args action arguments (URL, GET, POST)
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
if (!parent::prepare($args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
assert(!empty($cur)); // checked by parent
|
||||
|
||||
if (!$cur->hasRight(Right::SILENCEUSER)) {
|
||||
// TRANS: Client error on page to unsilence a user when the feature is not enabled.
|
||||
$this->clientError(_('You cannot silence users on this site.'));
|
||||
}
|
||||
|
||||
assert(!empty($this->profile)); // checked by parent
|
||||
|
||||
if (!$this->profile->isSilenced()) {
|
||||
// TRANS: Client error on page to unsilence a user when the to be unsilenced user has not been silenced.
|
||||
$this->clientError(_('User is not silenced.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Silence a user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
{
|
||||
$this->profile->unsilence();
|
||||
assert($this->scoped instanceof Profile);
|
||||
assert($this->profile instanceof Profile);
|
||||
|
||||
$this->profile->unsilenceAs($this->scoped);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-32
@@ -28,9 +28,7 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Miscellaneous settings actions
|
||||
@@ -83,7 +81,7 @@ class UrlsettingsAction extends SettingsAction
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_other',
|
||||
@@ -154,31 +152,13 @@ class UrlsettingsAction extends SettingsAction
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a post
|
||||
*
|
||||
* Saves the changes to url-shortening prefs and shows a success or failure
|
||||
* message.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handlePost()
|
||||
protected function doPost()
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
$urlshorteningservice = $this->trimmed('urlshorteningservice');
|
||||
|
||||
if (!is_null($urlshorteningservice) && strlen($urlshorteningservice) > 50) {
|
||||
// TRANS: Form validation error for form "Other settings" in user profile.
|
||||
$this->showForm(_('URL shortening service is too long (maximum 50 characters).'));
|
||||
return;
|
||||
throw new ClientException(_('URL shortening service is too long (maximum 50 characters).'));
|
||||
}
|
||||
|
||||
$maxurllength = $this->trimmed('maxurllength');
|
||||
@@ -195,9 +175,7 @@ class UrlsettingsAction extends SettingsAction
|
||||
throw new ClientException(_('Invalid number for maximum notice length.'));
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
assert(!is_null($user)); // should already be checked
|
||||
$user = $this->scoped->getUser();
|
||||
|
||||
$user->query('BEGIN');
|
||||
|
||||
@@ -209,14 +187,15 @@ class UrlsettingsAction extends SettingsAction
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
$user->query('ROLLBACK');
|
||||
// TRANS: Server error displayed when "Other" settings in user profile could not be updated on the server.
|
||||
$this->serverError(_('Could not update user.'));
|
||||
throw new ServerException(_('Could not update user.'));
|
||||
}
|
||||
|
||||
$prefs = User_urlshortener_prefs::getPrefs($user);
|
||||
$orig = null;
|
||||
|
||||
if (empty($prefs)) {
|
||||
if (!$prefs instanceof User_urlshortener_prefs) {
|
||||
$prefs = new User_urlshortener_prefs();
|
||||
|
||||
$prefs->user_id = $user->id;
|
||||
@@ -229,13 +208,14 @@ class UrlsettingsAction extends SettingsAction
|
||||
$prefs->maxurllength = $maxurllength;
|
||||
$prefs->maxnoticelength = $maxnoticelength;
|
||||
|
||||
if (!empty($orig)) {
|
||||
if ($orig instanceof User_urlshortener_prefs) {
|
||||
$result = $prefs->update($orig);
|
||||
} else {
|
||||
$result = $prefs->insert();
|
||||
}
|
||||
|
||||
if (!$result) {
|
||||
if ($result === null) {
|
||||
$user->query('ROLLBACK');
|
||||
// TRANS: Server exception thrown in profile URL settings when preferences could not be saved.
|
||||
throw new ServerException(_('Error saving user URL shortening preferences.'));
|
||||
}
|
||||
@@ -243,6 +223,6 @@ class UrlsettingsAction extends SettingsAction
|
||||
$user->query('COMMIT');
|
||||
|
||||
// TRANS: Confirmation message after saving preferences.
|
||||
$this->showForm(_('Preferences saved.'), true);
|
||||
return _('Preferences saved.');
|
||||
}
|
||||
}
|
||||
|
||||
+19
-44
@@ -28,9 +28,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* User by ID action class.
|
||||
@@ -42,50 +40,27 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class UserbyidAction extends Action
|
||||
class UserbyidAction extends ShowstreamAction
|
||||
{
|
||||
/**
|
||||
* Is read only?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
protected function doPreparation()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// accessing by ID just requires an ID, not a nickname
|
||||
$this->target = Profile::getByID($this->trimmed('id'));
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$id = $this->trimmed('id');
|
||||
if (!$id) {
|
||||
// TRANS: Client error displayed trying to find a user by ID without providing an ID.
|
||||
$this->clientError(_('No ID.'));
|
||||
// For local users when accessed by id number, redirect with
|
||||
// the nickname as argument instead of id.
|
||||
if ($this->target->isLocal()) {
|
||||
// Support redirecting to FOAF rdf/xml if the agent prefers it...
|
||||
// Internet Explorer doesn't specify "text/html" and does list "*/*"
|
||||
// at least through version 8. We need to list text/html up front to
|
||||
// ensure that only user-agents who specifically ask for RDF get it.
|
||||
$page_prefs = 'text/html,application/xhtml+xml,application/rdf+xml,application/xml;q=0.3,text/xml;q=0.2';
|
||||
$httpaccept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : null;
|
||||
$type = common_negotiate_type(common_accept_to_prefs($httpaccept),
|
||||
common_accept_to_prefs($page_prefs));
|
||||
$page = $type === 'application/rdf+xml' ? 'foaf' : 'showstream';
|
||||
$url = common_local_url($page, array('nickname' => $this->target->getNickname()));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
$user = User::getKV($id);
|
||||
if (!$user) {
|
||||
// TRANS: Client error displayed trying to find a user by ID for a non-existing ID.
|
||||
$this->clientError(_('No such user.'));
|
||||
}
|
||||
|
||||
// Support redirecting to FOAF rdf/xml if the agent prefers it...
|
||||
// Internet Explorer doesn't specify "text/html" and does list "*/*"
|
||||
// at least through version 8. We need to list text/html up front to
|
||||
// ensure that only user-agents who specifically ask for RDF get it.
|
||||
$page_prefs = 'text/html,application/xhtml+xml,application/rdf+xml,application/xml;q=0.3,text/xml;q=0.2';
|
||||
$httpaccept = isset($_SERVER['HTTP_ACCEPT'])
|
||||
? $_SERVER['HTTP_ACCEPT'] : null;
|
||||
$type = common_negotiate_type(common_accept_to_prefs($httpaccept),
|
||||
common_accept_to_prefs($page_prefs));
|
||||
$page = $type == 'application/rdf+xml' ? 'foaf' : 'showstream';
|
||||
$url = common_local_url($page, array('nickname' => $user->nickname));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
}
|
||||
|
||||
+54
-29
@@ -52,46 +52,71 @@ class UsergroupsAction extends GalleryAction
|
||||
if ($this->page == 1) {
|
||||
// TRANS: Page title for first page of groups for a user.
|
||||
// TRANS: %s is a nickname.
|
||||
return sprintf(_('%s groups'), $this->user->nickname);
|
||||
return sprintf(_('%s groups'), $this->getTarget()->getNickname());
|
||||
} else {
|
||||
// TRANS: Page title for all but the first page of groups for a user.
|
||||
// TRANS: %1$s is a nickname, %2$d is a page number.
|
||||
return sprintf(_('%1$s groups, page %2$d'),
|
||||
$this->user->nickname,
|
||||
$this->getTarget()->getNickname(),
|
||||
$this->page);
|
||||
}
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) {
|
||||
$this->element('p', 'instructions',
|
||||
// TRANS: Page notice for page with an overview of all subscribed groups
|
||||
// TRANS: of the logged in user's own profile.
|
||||
_('These are the groups whose notices '.
|
||||
'you listen to.'));
|
||||
} else {
|
||||
$this->element('p', 'instructions',
|
||||
// TRANS: Page notice for page with an overview of all groups a user other
|
||||
// TRANS: than the logged in user. %s is the user nickname.
|
||||
sprintf(_('These are the groups whose '.
|
||||
'notices %s listens to.'),
|
||||
$this->target->getNickname()));
|
||||
}
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('p', array('id' => 'new_group'));
|
||||
$this->element('a', array('href' => common_local_url('newgroup'),
|
||||
'class' => 'more'),
|
||||
// TRANS: Link text on group page to create a new group.
|
||||
_('Create a new group'));
|
||||
$this->elementEnd('p');
|
||||
|
||||
$this->elementStart('p', array('id' => 'group_search'));
|
||||
$this->element('a', array('href' => common_local_url('groupsearch'),
|
||||
'class' => 'more'),
|
||||
// TRANS: Link text on group page to search for groups.
|
||||
_('Search for more groups'));
|
||||
$this->elementEnd('p');
|
||||
if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) {
|
||||
$notice =
|
||||
// TRANS: Page notice of user's groups page.
|
||||
// TRANS: %%%%action.groupsearch%%%% and %%%%action.newgroup%%%% are URLs. Do not change them.
|
||||
// TRANS: This message contains Markdown links in the form [link text](link).
|
||||
sprintf(_('Groups let you find and talk with ' .
|
||||
'people of similar interests. ' .
|
||||
'You can [search for groups](%%%%action.groups%%%%) in your instance or ' .
|
||||
'[create a new group](%%%%action.newgroup%%%%). ' .
|
||||
'You can also follow groups ' .
|
||||
'from other GNU social instances: click on the remote button below ' .
|
||||
'and copy the group\'s link. ' .
|
||||
'You can find a list of GNU social groups [here](http://skilledtests.com/wiki/List_of_federated_GNU_social_groups)' .
|
||||
''));
|
||||
$this->elementStart('div', 'instructions');
|
||||
$this->raw(common_markup_to_html($notice));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
if (Event::handle('StartShowUserGroupsContent', array($this))) {
|
||||
$offset = ($this->page-1) * GROUPS_PER_PAGE;
|
||||
$limit = GROUPS_PER_PAGE + 1;
|
||||
|
||||
$groups = $this->user->getGroups($offset, $limit);
|
||||
$groups = $this->getTarget()->getGroups($offset, $limit);
|
||||
|
||||
if ($groups instanceof User_group) {
|
||||
$gl = new GroupList($groups, $this->user, $this);
|
||||
$gl = new GroupList($groups, $this->getTarget(), $this);
|
||||
$cnt = $gl->show();
|
||||
$this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE,
|
||||
$this->page, 'usergroups',
|
||||
array('nickname' => $this->user->nickname));
|
||||
} else {
|
||||
$this->showEmptyListMessage();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
} else {
|
||||
$this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE,
|
||||
$this->page, 'usergroups',
|
||||
array('nickname' => $this->getTarget()->getNickname()));
|
||||
}
|
||||
}
|
||||
|
||||
Event::handle('EndShowUserGroupsContent', array($this));
|
||||
@@ -102,16 +127,16 @@ class UsergroupsAction extends GalleryAction
|
||||
{
|
||||
// TRANS: Text on group page for a user that is not a member of any group.
|
||||
// TRANS: %s is a user nickname.
|
||||
$message = sprintf(_('%s is not a member of any group.'), $this->user->nickname) . ' ';
|
||||
|
||||
$message = sprintf(_('%s is not a member of any group.'), $this->getTarget()->getNickname()) . ' ';
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
if ($this->scoped->sameAs($this->getTarget())) {
|
||||
// TRANS: Text on group page for a user that is not a member of any group. This message contains
|
||||
// TRANS: a Markdown link in the form [link text](link) and a variable that should not be changed.
|
||||
$message .= _('Try [searching for groups](%%action.groupsearch%%) and joining them.');
|
||||
$message = _('You are not member of any group yet. After you join a group ' .
|
||||
'you can send messages to its members using the ' .
|
||||
'syntax "!groupname".');
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
@@ -119,7 +144,7 @@ class UsergroupsAction extends GalleryAction
|
||||
|
||||
function showProfileBlock()
|
||||
{
|
||||
$block = new AccountProfileBlock($this, $this->profile);
|
||||
$block = new AccountProfileBlock($this, $this->getTarget());
|
||||
$block->show();
|
||||
}
|
||||
}
|
||||
|
||||
+21
-67
@@ -17,100 +17,54 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once(INSTALLDIR.'/lib/rssaction.php');
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
// Formatting of RSS handled by Rss10Action
|
||||
|
||||
class UserrssAction extends Rss10Action
|
||||
class UserrssAction extends TargetedRss10Action
|
||||
{
|
||||
var $tag = null;
|
||||
protected $tag = null;
|
||||
|
||||
function prepare($args)
|
||||
protected function doStreamPreparation()
|
||||
{
|
||||
parent::prepare($args);
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$this->user = User::getKV('nickname', $nickname);
|
||||
parent::doStreamPreparation();
|
||||
|
||||
$this->tag = $this->trimmed('tag');
|
||||
}
|
||||
|
||||
if (!$this->user) {
|
||||
// TRANS: Client error displayed when user not found for an action.
|
||||
$this->clientError(_('No such user.'));
|
||||
}
|
||||
|
||||
protected function getNotices()
|
||||
{
|
||||
if (!empty($this->tag)) {
|
||||
$this->notices = $this->getTaggedNotices();
|
||||
} else {
|
||||
$this->notices = $this->getNotices();
|
||||
$stream = $this->getTarget()->getTaggedNotices($this->tag, 0, $this->limit);
|
||||
return $stream->fetchAll();
|
||||
}
|
||||
// otherwise we fetch a normal user stream
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTaggedNotices()
|
||||
{
|
||||
$notice = $this->user->getTaggedNotices(
|
||||
$this->tag,
|
||||
0,
|
||||
($this->limit == 0) ? NOTICES_PER_PAGE : $this->limit,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
$notices = array();
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
|
||||
function getNotices()
|
||||
{
|
||||
$notice = $this->user->getNotices(
|
||||
0,
|
||||
($this->limit == 0) ? NOTICES_PER_PAGE : $this->limit
|
||||
);
|
||||
|
||||
$notices = array();
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
$stream = $this->getTarget()->getNotices(0, $this->limit);
|
||||
return $stream->fetchAll();
|
||||
}
|
||||
|
||||
function getChannel()
|
||||
{
|
||||
$user = $this->user;
|
||||
$profile = $user->getProfile();
|
||||
$c = array('url' => common_local_url('userrss',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
$this->target->getNickname())),
|
||||
// TRANS: Message is used as link title. %s is a user nickname.
|
||||
'title' => sprintf(_('%s timeline'), $user->nickname),
|
||||
'link' => $profile->profileurl,
|
||||
'title' => sprintf(_('%s timeline'), $this->target->getNickname()),
|
||||
'link' => $this->target->getUrl(),
|
||||
// TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
|
||||
'description' => sprintf(_('Updates from %1$s on %2$s!'),
|
||||
$user->nickname, common_config('site', 'name')));
|
||||
$this->target->getNickname(), common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
function getImage()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
return $profile->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
}
|
||||
|
||||
// override parent to add X-SUP-ID URL
|
||||
|
||||
function initRss($limit=0)
|
||||
function initRss()
|
||||
{
|
||||
$url = common_local_url('sup', null, null, $this->user->id);
|
||||
$url = common_local_url('sup', null, null, $this->target->getID());
|
||||
header('X-SUP-ID: '.$url);
|
||||
parent::initRss($limit);
|
||||
parent::initRss();
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
|
||||
+16
-11
@@ -22,7 +22,7 @@ class Attention extends Managed_DataObject
|
||||
public $__table = 'attention'; // table name
|
||||
public $notice_id; // int(4) primary_key not_null
|
||||
public $profile_id; // int(4) primary_key not_null
|
||||
public $reason; // varchar(255)
|
||||
public $reason; // varchar(191) not 255 because utf8mb4 takes more space
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
@@ -33,7 +33,7 @@ class Attention extends Managed_DataObject
|
||||
'fields' => array(
|
||||
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice_id to give attention'),
|
||||
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile_id for feed receiver'),
|
||||
'reason' => array('type' => 'varchar', 'length' => 255, 'description' => 'Optional reason why this was brought to the attention of profile_id'),
|
||||
'reason' => array('type' => 'varchar', 'length' => 191, 'description' => 'Optional reason why this was brought to the attention of profile_id'),
|
||||
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
|
||||
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
|
||||
),
|
||||
@@ -49,18 +49,23 @@ class Attention extends Managed_DataObject
|
||||
);
|
||||
}
|
||||
|
||||
public static function saveNew(Notice $notice, Profile $profile, $reason=null)
|
||||
public static function saveNew(Notice $notice, Profile $target, $reason=null)
|
||||
{
|
||||
$att = new Attention();
|
||||
try {
|
||||
$att = Attention::getByKeys(['notice_id'=>$notice->getID(), 'profile_id'=>$target->getID()]);
|
||||
throw new AlreadyFulfilledException('Attention already exists with reason: '.var_export($att->reason,true));
|
||||
} catch (NoResultException $e) {
|
||||
$att = new Attention();
|
||||
|
||||
$att->notice_id = $notice->getID();
|
||||
$att->profile_id = $profile->getID();
|
||||
$att->reason = $reason;
|
||||
$att->created = common_sql_now();
|
||||
$result = $att->insert();
|
||||
$att->notice_id = $notice->getID();
|
||||
$att->profile_id = $target->getID();
|
||||
$att->reason = $reason;
|
||||
$att->created = common_sql_now();
|
||||
$result = $att->insert();
|
||||
|
||||
if ($result === false) {
|
||||
throw new Exception('Could not saveNew in Attention');
|
||||
if ($result === false) {
|
||||
throw new Exception('Failed Attention::saveNew for notice id=='.$notice->getID().' target id=='.$target->getID().', reason=="'.$reason.'"');
|
||||
}
|
||||
}
|
||||
return $att;
|
||||
}
|
||||
|
||||
+16
-32
@@ -1,27 +1,22 @@
|
||||
<?php
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Table Definition for avatar
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Avatar extends Managed_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'avatar'; // table name
|
||||
public $profile_id; // int(4) primary_key not_null
|
||||
public $original; // tinyint(1)
|
||||
public $width; // int(4) primary_key not_null
|
||||
public $height; // int(4) primary_key not_null
|
||||
public $mediatype; // varchar(32) not_null
|
||||
public $filename; // varchar(255)
|
||||
public $url; // varchar(255) unique_key
|
||||
public $filename; // varchar(191) not 255 because utf8mb4 takes more space
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
public static function schemaDef()
|
||||
{
|
||||
@@ -32,14 +27,13 @@ class Avatar extends Managed_DataObject
|
||||
'width' => array('type' => 'int', 'not null' => true, 'description' => 'image width'),
|
||||
'height' => array('type' => 'int', 'not null' => true, 'description' => 'image height'),
|
||||
'mediatype' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'file type'),
|
||||
'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'local filename, if local'),
|
||||
'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'avatar location'),
|
||||
'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'local filename, if local'),
|
||||
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
|
||||
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
|
||||
),
|
||||
'primary key' => array('profile_id', 'width', 'height'),
|
||||
'unique keys' => array(
|
||||
'avatar_url_key' => array('url'),
|
||||
// 'avatar_filename_key' => array('filename'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'avatar_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
|
||||
@@ -193,16 +187,7 @@ class Avatar extends Managed_DataObject
|
||||
$server = common_config('site', 'server');
|
||||
}
|
||||
|
||||
$ssl = common_config('avatar', 'ssl');
|
||||
|
||||
if (is_null($ssl)) { // null -> guess
|
||||
if (common_config('site', 'ssl') == 'always' &&
|
||||
!common_config('avatar', 'server')) {
|
||||
$ssl = true;
|
||||
} else {
|
||||
$ssl = false;
|
||||
}
|
||||
}
|
||||
$ssl = (common_config('avatar', 'ssl') || GNUsocial::useHTTPS());
|
||||
|
||||
$protocol = ($ssl) ? 'https' : 'http';
|
||||
|
||||
@@ -211,12 +196,7 @@ class Avatar extends Managed_DataObject
|
||||
|
||||
function displayUrl()
|
||||
{
|
||||
$server = common_config('avatar', 'server');
|
||||
if ($server && !empty($this->filename)) {
|
||||
return Avatar::url($this->filename);
|
||||
} else {
|
||||
return $this->url;
|
||||
}
|
||||
return Avatar::url($this->filename);
|
||||
}
|
||||
|
||||
static function urlByProfile(Profile $target, $width=null, $height=null) {
|
||||
@@ -241,17 +221,21 @@ class Avatar extends Managed_DataObject
|
||||
// TRANS: An error message when avatar size is unreasonable
|
||||
throw new Exception(_m('Avatar size too large'));
|
||||
}
|
||||
// So far we only have square avatars and I don't have time to
|
||||
// rewrite support for non-square ones right now ;)
|
||||
$height = $width;
|
||||
|
||||
$original = Avatar::getUploaded($target);
|
||||
|
||||
$imagefile = new ImageFile($target->id, Avatar::path($original->filename));
|
||||
$filename = $imagefile->resize($width);
|
||||
$imagefile = new ImageFile(null, Avatar::path($original->filename));
|
||||
$filename = Avatar::filename($target->getID(), image_type_to_extension($imagefile->preferredType()),
|
||||
$width, common_timestamp());
|
||||
$imagefile->resizeTo(Avatar::path($filename), array('width'=>$width, 'height'=>$height));
|
||||
|
||||
$scaled = clone($original);
|
||||
$scaled->original = false;
|
||||
$scaled->width = $width;
|
||||
$scaled->height = $width;
|
||||
$scaled->url = Avatar::url($filename);
|
||||
$scaled->height = $height;
|
||||
$scaled->filename = $filename;
|
||||
$scaled->created = common_sql_now();
|
||||
|
||||
|
||||
@@ -17,16 +17,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Table Definition for config
|
||||
*/
|
||||
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Config extends Managed_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
@@ -35,7 +31,7 @@ class Config extends Managed_DataObject
|
||||
public $__table = 'config'; // table name
|
||||
public $section; // varchar(32) primary_key not_null
|
||||
public $setting; // varchar(32) primary_key not_null
|
||||
public $value; // varchar(255)
|
||||
public $value; // text
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
@@ -46,7 +42,7 @@ class Config extends Managed_DataObject
|
||||
'fields' => array(
|
||||
'section' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'default' => '', 'description' => 'configuration section'),
|
||||
'setting' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'default' => '', 'description' => 'configuration setting'),
|
||||
'value' => array('type' => 'varchar', 'length' => 255, 'description' => 'configuration value'),
|
||||
'value' => array('type' => 'text', 'description' => 'configuration value'),
|
||||
),
|
||||
'primary key' => array('section', 'setting'),
|
||||
);
|
||||
|
||||
@@ -2,34 +2,27 @@
|
||||
/**
|
||||
* Table Definition for confirm_address
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Confirm_address extends Managed_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'confirm_address'; // table name
|
||||
public $code; // varchar(32) primary_key not_null
|
||||
public $user_id; // int(4) not_null
|
||||
public $address; // varchar(255) not_null
|
||||
public $address_extra; // varchar(255) not_null
|
||||
public $address; // varchar(191) not_null not 255 because utf8mb4 takes more space
|
||||
public $address_extra; // varchar(191) not_null not 255 because utf8mb4 takes more space
|
||||
public $address_type; // varchar(8) not_null
|
||||
public $claimed; // datetime()
|
||||
public $sent; // datetime()
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
public static function schemaDef()
|
||||
{
|
||||
return array(
|
||||
'fields' => array(
|
||||
'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'good random code'),
|
||||
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who requested confirmation'),
|
||||
'address' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'address (email, xmpp, SMS, etc.)'),
|
||||
'address_extra' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'carrier ID, for SMS'),
|
||||
'address' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'address (email, xmpp, SMS, etc.)'),
|
||||
'address_extra' => array('type' => 'varchar', 'length' => 191, 'description' => 'carrier ID, for SMS'),
|
||||
'address_type' => array('type' => 'varchar', 'length' => 8, 'not null' => true, 'description' => 'address type ("email", "xmpp", "sms")'),
|
||||
'claimed' => array('type' => 'datetime', 'description' => 'date this was claimed for queueing'),
|
||||
'sent' => array('type' => 'datetime', 'description' => 'date this was sent for queueing'),
|
||||
|
||||
@@ -10,8 +10,8 @@ class Consumer extends Managed_DataObject
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'consumer'; // table name
|
||||
public $consumer_key; // varchar(255) primary_key not_null
|
||||
public $consumer_secret; // varchar(255) not_null
|
||||
public $consumer_key; // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
|
||||
public $consumer_secret; // varchar(191) not_null not 255 because utf8mb4 takes more space
|
||||
public $seed; // char(32) not_null
|
||||
public $created; // datetime not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
@@ -24,8 +24,8 @@ class Consumer extends Managed_DataObject
|
||||
return array(
|
||||
'description' => 'OAuth consumer record',
|
||||
'fields' => array(
|
||||
'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'unique identifier, root URL'),
|
||||
'consumer_secret' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'secret value'),
|
||||
'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'unique identifier, root URL'),
|
||||
'consumer_secret' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'secret value'),
|
||||
'seed' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'seed for new tokens by this consumer'),
|
||||
|
||||
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
|
||||
|
||||
+52
-27
@@ -34,8 +34,8 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
class Conversation extends Managed_DataObject
|
||||
{
|
||||
public $__table = 'conversation'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $uri; // varchar(255) unique_key
|
||||
public $id; // int(4) primary_key not_null auto_increment
|
||||
public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
|
||||
public $created; // datetime not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
@@ -43,8 +43,8 @@ class Conversation extends Managed_DataObject
|
||||
{
|
||||
return array(
|
||||
'fields' => array(
|
||||
'id' => array('type' => 'int', 'not null' => true, 'description' => 'should be set from root notice id (since 2014-03-01 commit)'),
|
||||
'uri' => array('type' => 'varchar', 'not null'=>true, 'length' => 255, 'description' => 'URI of the conversation'),
|
||||
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique identifier, (again) unrelated to notice id since 2016-01-06'),
|
||||
'uri' => array('type' => 'varchar', 'not null'=>true, 'length' => 191, 'description' => 'URI of the conversation'),
|
||||
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
|
||||
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
|
||||
),
|
||||
@@ -55,6 +55,32 @@ class Conversation extends Managed_DataObject
|
||||
);
|
||||
}
|
||||
|
||||
static public function beforeSchemaUpdate()
|
||||
{
|
||||
$table = strtolower(get_called_class());
|
||||
$schema = Schema::get();
|
||||
$schemadef = $schema->getTableDef($table);
|
||||
|
||||
// 2016-01-06 We have to make sure there is no conversation with id==0 since it will screw up auto increment resequencing
|
||||
if ($schemadef['fields']['id']['auto_increment']) {
|
||||
// since we already have auto incrementing ('serial') we can continue
|
||||
return;
|
||||
}
|
||||
|
||||
// The conversation will be recreated in upgrade.php, which will
|
||||
// generate a new URI, but that's collateral damage for you.
|
||||
$conv = new Conversation();
|
||||
$conv->id = 0;
|
||||
if ($conv->find()) {
|
||||
while ($conv->fetch()) {
|
||||
// Since we have filtered on 0 this only deletes such entries
|
||||
// which I have been afraid wouldn't work, but apparently does!
|
||||
// (I thought it would act as null or something and find _all_ conversation entries)
|
||||
$conv->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating a new conversation.
|
||||
*
|
||||
@@ -63,25 +89,17 @@ class Conversation extends Managed_DataObject
|
||||
*
|
||||
* @return Conversation the new conversation DO
|
||||
*/
|
||||
static function create(Notice $notice, $uri=null)
|
||||
static function create($uri=null, $created=null)
|
||||
{
|
||||
if (empty($notice->id)) {
|
||||
throw new ServerException(_('Tried to create conversation for not yet inserted notice'));
|
||||
}
|
||||
// Be aware that the Notice does not have an id yet since it's not inserted!
|
||||
$conv = new Conversation();
|
||||
$conv->created = common_sql_now();
|
||||
$conv->id = $notice->id;
|
||||
$conv->uri = $uri ?: sprintf('%s%s=%d:%s=%s:%s=%x',
|
||||
$conv->created = $created ?: common_sql_now();
|
||||
$conv->uri = $uri ?: sprintf('%s%s=%s:%s=%s',
|
||||
TagURI::mint(),
|
||||
'noticeId', $notice->id,
|
||||
'objectType', 'thread',
|
||||
'crc32', crc32($notice->content));
|
||||
$result = $conv->insert();
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($conv, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('Failed to create conversation for notice'));
|
||||
}
|
||||
'nonce', common_random_hexstr(8));
|
||||
// This insert throws exceptions on failure
|
||||
$conv->insert();
|
||||
|
||||
return $conv;
|
||||
}
|
||||
@@ -108,8 +126,8 @@ class Conversation extends Managed_DataObject
|
||||
|
||||
static public function getUrlFromNotice(Notice $notice, $anchor=true)
|
||||
{
|
||||
$conv = self::getKV('id', $notice->conversation);
|
||||
return $conv->getUrl($anchor ? $notice->id : null);
|
||||
$conv = Conversation::getByID($notice->conversation);
|
||||
return $conv->getUrl($anchor ? $notice->getID() : null);
|
||||
}
|
||||
|
||||
public function getUri()
|
||||
@@ -120,18 +138,25 @@ class Conversation extends Managed_DataObject
|
||||
public function getUrl($noticeId=null)
|
||||
{
|
||||
// FIXME: the URL router should take notice-id as an argument...
|
||||
return common_local_url('conversation', array('id' => $this->id)) .
|
||||
return common_local_url('conversation', array('id' => $this->getID())) .
|
||||
($noticeId===null ? '' : "#notice-{$noticeId}");
|
||||
}
|
||||
|
||||
// FIXME: ...will 500 ever be too low? Taken from ConversationAction::MAX_NOTICES
|
||||
public function getNotices($offset=0, $limit=500, Profile $scoped=null)
|
||||
public function getNotices(Profile $scoped=null, $offset=0, $limit=500)
|
||||
{
|
||||
if ($scoped === null) {
|
||||
$scoped = Profile::current();
|
||||
}
|
||||
$stream = new ConversationNoticeStream($this->id, $scoped);
|
||||
$stream = new ConversationNoticeStream($this->getID(), $scoped);
|
||||
$notices = $stream->getNotices($offset, $limit);
|
||||
return $notices;
|
||||
}
|
||||
|
||||
public function insert()
|
||||
{
|
||||
$result = parent::insert();
|
||||
if ($result === false) {
|
||||
common_log_db_error($this, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('Failed to insert Conversation into database'));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, Control Yourself, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Table Definition for notice
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Deleted_notice extends Managed_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'deleted_notice'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $profile_id; // int(4) not_null
|
||||
public $uri; // varchar(255) unique_key
|
||||
public $created; // datetime() not_null
|
||||
public $deleted; // datetime() not_null
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
public static function schemaDef()
|
||||
{
|
||||
return array(
|
||||
'fields' => array(
|
||||
'id' => array('type' => 'int', 'not null' => true, 'description' => 'identity of notice'),
|
||||
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'author of the notice'),
|
||||
'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
|
||||
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice record was created'),
|
||||
'deleted' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice record was created'),
|
||||
),
|
||||
'primary key' => array('id'),
|
||||
'unique keys' => array(
|
||||
'deleted_notice_uri_key' => array('uri'),
|
||||
),
|
||||
'indexes' => array(
|
||||
'deleted_notice_profile_id_idx' => array('profile_id'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+263
-170
@@ -26,29 +26,36 @@ class File extends Managed_DataObject
|
||||
{
|
||||
public $__table = 'file'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $url; // varchar(255) unique_key
|
||||
public $urlhash; // varchar(64) unique_key
|
||||
public $url; // text
|
||||
public $filehash; // varchar(64) indexed
|
||||
public $mimetype; // varchar(50)
|
||||
public $size; // int(4)
|
||||
public $title; // varchar(255)
|
||||
public $title; // text()
|
||||
public $date; // int(4)
|
||||
public $protected; // int(4)
|
||||
public $filename; // varchar(255)
|
||||
public $filename; // text()
|
||||
public $width; // int(4)
|
||||
public $height; // int(4)
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
const URLHASH_ALG = 'sha256';
|
||||
const FILEHASH_ALG = 'sha256';
|
||||
|
||||
public static function schemaDef()
|
||||
{
|
||||
return array(
|
||||
'fields' => array(
|
||||
'id' => array('type' => 'serial', 'not null' => true),
|
||||
'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'destination URL after following redirections'),
|
||||
'urlhash' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'sha256 of destination URL (url field)'),
|
||||
'url' => array('type' => 'text', 'description' => 'destination URL after following possible redirections'),
|
||||
'filehash' => array('type' => 'varchar', 'length' => 64, 'not null' => false, 'description' => 'sha256 of the file contents, only for locally stored files of course'),
|
||||
'mimetype' => array('type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'),
|
||||
'size' => array('type' => 'int', 'description' => 'size of resource when available'),
|
||||
'title' => array('type' => 'varchar', 'length' => 255, 'description' => 'title of resource when available'),
|
||||
'title' => array('type' => 'text', 'description' => 'title of resource when available'),
|
||||
'date' => array('type' => 'int', 'description' => 'date of resource according to http query'),
|
||||
'protected' => array('type' => 'int', 'description' => 'true when URL is private (needs login)'),
|
||||
'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'if a local file, name of the file'),
|
||||
'filename' => array('type' => 'text', 'description' => 'if file is stored locally (too) this is the filename'),
|
||||
'width' => array('type' => 'int', 'description' => 'width in pixels, if it can be described as such and data is available'),
|
||||
'height' => array('type' => 'int', 'description' => 'height in pixels, if it can be described as such and data is available'),
|
||||
|
||||
@@ -56,13 +63,28 @@ class File extends Managed_DataObject
|
||||
),
|
||||
'primary key' => array('id'),
|
||||
'unique keys' => array(
|
||||
'file_url_key' => array('url'),
|
||||
'file_urlhash_key' => array('urlhash'),
|
||||
),
|
||||
'indexes' => array(
|
||||
'file_filehash_idx' => array('filehash'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function isProtected($url) {
|
||||
return 'http://www.facebook.com/login.php' === $url;
|
||||
public static function isProtected($url) {
|
||||
|
||||
$protected_urls_exps = array(
|
||||
'https://www.facebook.com/login.php',
|
||||
common_path('main/login')
|
||||
);
|
||||
|
||||
foreach ($protected_urls_exps as $protected_url_exp) {
|
||||
if (preg_match('!^'.preg_quote($protected_url_exp).'(.*)$!i', $url) === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,29 +94,45 @@ class File extends Managed_DataObject
|
||||
* @param string $given_url
|
||||
* @return File
|
||||
*/
|
||||
public static function saveNew(array $redir_data, $given_url) {
|
||||
|
||||
// I don't know why we have to keep doing this but I'm adding this last check to avoid
|
||||
// uniqueness bugs.
|
||||
|
||||
$file = File::getKV('url', $given_url);
|
||||
|
||||
if (!$file instanceof File) {
|
||||
$file = new File;
|
||||
$file->url = $given_url;
|
||||
if (!empty($redir_data['protected'])) $file->protected = $redir_data['protected'];
|
||||
if (!empty($redir_data['title'])) $file->title = $redir_data['title'];
|
||||
if (!empty($redir_data['type'])) $file->mimetype = $redir_data['type'];
|
||||
if (!empty($redir_data['size'])) $file->size = intval($redir_data['size']);
|
||||
if (isset($redir_data['time']) && $redir_data['time'] > 0) $file->date = intval($redir_data['time']);
|
||||
$file_id = $file->insert();
|
||||
public static function saveNew(array $redir_data, $given_url)
|
||||
{
|
||||
$file = null;
|
||||
try {
|
||||
// I don't know why we have to keep doing this but we run a last check to avoid
|
||||
// uniqueness bugs.
|
||||
$file = File::getByUrl($given_url);
|
||||
return $file;
|
||||
} catch (NoResultException $e) {
|
||||
// We don't have the file's URL since before, so let's continue.
|
||||
}
|
||||
|
||||
Event::handle('EndFileSaveNew', array($file, $redir_data, $given_url));
|
||||
assert ($file instanceof File);
|
||||
$file = new File;
|
||||
$file->url = $given_url;
|
||||
if (!empty($redir_data['protected'])) $file->protected = $redir_data['protected'];
|
||||
if (!empty($redir_data['title'])) $file->title = $redir_data['title'];
|
||||
if (!empty($redir_data['type'])) $file->mimetype = $redir_data['type'];
|
||||
if (!empty($redir_data['size'])) $file->size = intval($redir_data['size']);
|
||||
if (isset($redir_data['time']) && $redir_data['time'] > 0) $file->date = intval($redir_data['time']);
|
||||
$file->saveFile();
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function saveFile() {
|
||||
$this->urlhash = self::hashurl($this->url);
|
||||
|
||||
if (!Event::handle('StartFileSaveNew', array(&$this))) {
|
||||
throw new ServerException('File not saved due to an aborted StartFileSaveNew event.');
|
||||
}
|
||||
|
||||
$this->id = $this->insert();
|
||||
|
||||
if ($this->id === false) {
|
||||
throw new ServerException('File/URL metadata could not be saved to the database.');
|
||||
}
|
||||
|
||||
Event::handle('EndFileSaveNew', array($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Go look at a URL and possibly save data about it if it's new:
|
||||
* - follow redirect chains and store them in file_redirection
|
||||
@@ -103,16 +141,15 @@ class File extends Managed_DataObject
|
||||
* - optionally save a file_to_post record
|
||||
* - return the File object with the full reference
|
||||
*
|
||||
* @fixme refactor this mess, it's gotten pretty scary.
|
||||
* @param string $given_url the URL we're looking at
|
||||
* @param int $notice_id (optional)
|
||||
* @param Notice $notice (optional)
|
||||
* @param bool $followRedirects defaults to true
|
||||
*
|
||||
* @return mixed File on success, -1 on some errors
|
||||
*
|
||||
* @throws ServerException on failure
|
||||
*/
|
||||
public static function processNew($given_url, $notice_id=null, $followRedirects=true) {
|
||||
public static function processNew($given_url, Notice $notice=null, $followRedirects=true) {
|
||||
if (empty($given_url)) {
|
||||
throw new ServerException('No given URL to process');
|
||||
}
|
||||
@@ -122,64 +159,18 @@ class File extends Managed_DataObject
|
||||
throw new ServerException('No canonical URL from given URL to process');
|
||||
}
|
||||
|
||||
$file = File::getKV('url', $given_url);
|
||||
if (!$file instanceof File) {
|
||||
// First check if we have a lookup trace for this URL already
|
||||
$file_redir = File_redirection::getKV('url', $given_url);
|
||||
if ($file_redir instanceof File_redirection) {
|
||||
$file = File::getKV('id', $file_redir->file_id);
|
||||
if (!$file instanceof File) {
|
||||
// File did not exist, let's clean up the File_redirection entry
|
||||
$file_redir->delete();
|
||||
}
|
||||
}
|
||||
$redir = File_redirection::where($given_url);
|
||||
$file = $redir->getFile();
|
||||
|
||||
// If we still don't have a File object, let's create one now!
|
||||
if (!$file instanceof File) {
|
||||
// @fixme for new URLs this also looks up non-redirect data
|
||||
// such as target content type, size, etc, which we need
|
||||
// for File::saveNew(); so we call it even if not following
|
||||
// new redirects.
|
||||
$redir_data = File_redirection::where($given_url);
|
||||
if (is_array($redir_data)) {
|
||||
$redir_url = $redir_data['url'];
|
||||
} elseif (is_string($redir_data)) {
|
||||
$redir_url = $redir_data;
|
||||
$redir_data = array();
|
||||
} else {
|
||||
// TRANS: Server exception thrown when a URL cannot be processed.
|
||||
throw new ServerException(sprintf(_("Cannot process URL '%s'"), $given_url));
|
||||
}
|
||||
|
||||
// TODO: max field length
|
||||
if ($redir_url === $given_url || strlen($redir_url) > 255 || !$followRedirects) {
|
||||
// Save the File object based on our lookup trace
|
||||
$file = File::saveNew($redir_data, $given_url);
|
||||
} else {
|
||||
// This seems kind of messed up... for now skipping this part
|
||||
// if we're already under a redirect, so we don't go into
|
||||
// horrible infinite loops if we've been given an unstable
|
||||
// redirect (where the final destination of the first request
|
||||
// doesn't match what we get when we ask for it again).
|
||||
//
|
||||
// Seen in the wild with clojure.org, which redirects through
|
||||
// wikispaces for auth and appends session data in the URL params.
|
||||
$file = self::processNew($redir_url, $notice_id, /*followRedirects*/false);
|
||||
File_redirection::saveNew($redir_data, $file->id, $given_url);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$file instanceof File) {
|
||||
// This should only happen if File::saveNew somehow did not return a File object,
|
||||
// though we have an assert for that in case the event there might've gone wrong.
|
||||
// If anything else goes wrong, there should've been an exception thrown.
|
||||
throw new ServerException('URL processing failed without new File object');
|
||||
}
|
||||
if (!$file instanceof File || empty($file->id)) {
|
||||
// This should not happen
|
||||
throw new ServerException('URL processing failed without new File object');
|
||||
}
|
||||
|
||||
if (!empty($notice_id)) {
|
||||
File_to_post::processNew($file->id, $notice_id);
|
||||
if ($notice instanceof Notice) {
|
||||
File_to_post::processNew($file, $notice);
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
@@ -233,16 +224,20 @@ class File extends Managed_DataObject
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getFilename()
|
||||
{
|
||||
if (!self::validFilename($this->filename)) {
|
||||
// TRANS: Client exception thrown if a file upload does not have a valid name.
|
||||
throw new ClientException(_("Invalid filename."));
|
||||
}
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
// where should the file go?
|
||||
|
||||
static function filename(Profile $profile, $origname, $mimetype)
|
||||
{
|
||||
try {
|
||||
$ext = common_supported_mime_to_ext($mimetype);
|
||||
} catch (Exception $e) {
|
||||
// We don't support this mimetype, but let's guess the extension
|
||||
$ext = substr(strrchr($mimetype, '/'), 1);
|
||||
}
|
||||
$ext = self::guessMimeExtension($mimetype);
|
||||
|
||||
// Normalize and make the original filename more URL friendly.
|
||||
$origname = basename($origname, ".$ext");
|
||||
@@ -263,6 +258,21 @@ class File extends Managed_DataObject
|
||||
return $filename;
|
||||
}
|
||||
|
||||
static function guessMimeExtension($mimetype)
|
||||
{
|
||||
try {
|
||||
$ext = common_supported_mime_to_ext($mimetype);
|
||||
} catch (Exception $e) {
|
||||
// We don't support this mimetype, but let's guess the extension
|
||||
$matches = array();
|
||||
if (!preg_match('/\/([a-z0-9]+)/', mb_strtolower($mimetype), $matches)) {
|
||||
throw new Exception('Malformed mimetype: '.$mimetype);
|
||||
}
|
||||
$ext = $matches[1];
|
||||
}
|
||||
return mb_strtolower($ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for as-saved base filenames
|
||||
*/
|
||||
@@ -303,7 +313,7 @@ class File extends Managed_DataObject
|
||||
|
||||
}
|
||||
|
||||
if (StatusNet::useHTTPS()) {
|
||||
if (GNUsocial::useHTTPS()) {
|
||||
|
||||
$sslserver = common_config('attachments', 'sslserver');
|
||||
|
||||
@@ -350,28 +360,48 @@ class File extends Managed_DataObject
|
||||
return $protocol.'://'.$server.$path.$filename;
|
||||
}
|
||||
|
||||
static $_enclosures = array();
|
||||
|
||||
function getEnclosure(){
|
||||
$enclosure = (object) array();
|
||||
foreach (array('title', 'url', 'date', 'modified', 'size', 'mimetype') as $key) {
|
||||
$enclosure->$key = $this->$key;
|
||||
if (isset(self::$_enclosures[$this->getID()])) {
|
||||
return self::$_enclosures[$this->getID()];
|
||||
}
|
||||
|
||||
$needMoreMetadataMimetypes = array(null, 'application/xhtml+xml');
|
||||
$enclosure = (object) array();
|
||||
foreach (array('title', 'url', 'date', 'modified', 'size', 'mimetype', 'width', 'height') as $key) {
|
||||
if ($this->$key !== '') {
|
||||
$enclosure->$key = $this->$key;
|
||||
}
|
||||
}
|
||||
|
||||
$needMoreMetadataMimetypes = array(null, 'application/xhtml+xml', 'text/html');
|
||||
|
||||
if (!isset($this->filename) && in_array(common_bare_mime($enclosure->mimetype), $needMoreMetadataMimetypes)) {
|
||||
// This fetches enclosure metadata for non-local links with unset/HTML mimetypes,
|
||||
// which may be enriched through oEmbed or similar (implemented as plugins)
|
||||
Event::handle('FileEnclosureMetadata', array($this, &$enclosure));
|
||||
}
|
||||
if (empty($enclosure->mimetype) || in_array(common_bare_mime($enclosure->mimetype), $needMoreMetadataMimetypes)) {
|
||||
if (empty($enclosure->mimetype)) {
|
||||
// This means we either don't know what it is, so it can't
|
||||
// be shown as an enclosure, or it is an HTML link which
|
||||
// does not link to a resource with further metadata.
|
||||
throw new ServerException('Unknown enclosure mimetype, not enough metadata');
|
||||
}
|
||||
|
||||
self::$_enclosures[$this->getID()] = $enclosure;
|
||||
return $enclosure;
|
||||
}
|
||||
|
||||
public function hasThumbnail()
|
||||
{
|
||||
try {
|
||||
$this->getThumbnail();
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachment's thumbnail record, if any.
|
||||
* Make sure you supply proper 'int' typed variables (or null).
|
||||
@@ -381,8 +411,12 @@ class File extends Managed_DataObject
|
||||
* @param $crop bool Crop to the max-values' aspect ratio
|
||||
*
|
||||
* @return File_thumbnail
|
||||
*
|
||||
* @throws UseFileAsThumbnailException if the file is considered an image itself and should be itself as thumbnail
|
||||
* @throws UnsupportedMediaException if, despite trying, we can't understand how to make a thumbnail for this format
|
||||
* @throws ServerException on various other errors
|
||||
*/
|
||||
public function getThumbnail($width=null, $height=null, $crop=false, $force_still=true)
|
||||
public function getThumbnail($width=null, $height=null, $crop=false, $force_still=true, $upscale=null)
|
||||
{
|
||||
// Get some more information about this file through our ImageFile class
|
||||
$image = ImageFile::fromFileObject($this);
|
||||
@@ -394,99 +428,67 @@ class File extends Managed_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
if ($width === null) {
|
||||
$width = common_config('thumbnail', 'width');
|
||||
$height = common_config('thumbnail', 'height');
|
||||
$crop = common_config('thumbnail', 'crop');
|
||||
}
|
||||
|
||||
if ($height === null) {
|
||||
$height = $width;
|
||||
$crop = true;
|
||||
}
|
||||
|
||||
// Get proper aspect ratio width and height before lookup
|
||||
// We have to do it through an ImageFile object because of orientation etc.
|
||||
// Only other solution would've been to rotate + rewrite uploaded files.
|
||||
list($width, $height, $x, $y, $w, $h) =
|
||||
$image->scaleToFit($width, $height, $crop);
|
||||
|
||||
$params = array('file_id'=> $this->id,
|
||||
'width' => $width,
|
||||
'height' => $height);
|
||||
$thumb = File_thumbnail::pkeyGet($params);
|
||||
if ($thumb instanceof File_thumbnail) {
|
||||
return $thumb;
|
||||
}
|
||||
|
||||
// throws exception on failure to generate thumbnail
|
||||
$outname = "thumb-{$width}x{$height}-" . $image->filename;
|
||||
$outpath = self::path($outname);
|
||||
|
||||
// The boundary box for our resizing
|
||||
$box = array('width'=>$width, 'height'=>$height,
|
||||
'x'=>$x, 'y'=>$y,
|
||||
'w'=>$w, 'h'=>$h);
|
||||
|
||||
// Doublecheck that parameters are sane and integers.
|
||||
if ($box['width'] < 1 || $box['width'] > common_config('thumbnail', 'maxsize')
|
||||
|| $box['height'] < 1 || $box['height'] > common_config('thumbnail', 'maxsize')
|
||||
|| $box['w'] < 1 || $box['x'] >= $image->width
|
||||
|| $box['h'] < 1 || $box['y'] >= $image->height) {
|
||||
// Fail on bad width parameter. If this occurs, it's due to algorithm in ImageFile->scaleToFit
|
||||
common_debug("Boundary box parameters for resize of {$image->filepath} : ".var_export($box,true));
|
||||
throw new ServerException('Bad thumbnail size parameters.');
|
||||
}
|
||||
|
||||
common_debug(sprintf('Generating a thumbnail of File id==%u of size %ux%u', $this->id, $width, $height));
|
||||
// Perform resize and store into file
|
||||
$image->resizeTo($outpath, $box);
|
||||
|
||||
// Avoid deleting the original
|
||||
if ($image->getPath() != self::path($image->filename)) {
|
||||
$image->unlink();
|
||||
}
|
||||
return File_thumbnail::saveThumbnail($this->id,
|
||||
self::url($outname),
|
||||
$width, $height,
|
||||
$outname);
|
||||
return $image->getFileThumbnail($width, $height, $crop,
|
||||
!is_null($upscale) ? $upscale : common_config('thumbnail', 'upscale'));
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
{
|
||||
return self::path($this->filename);
|
||||
$filepath = self::path($this->filename);
|
||||
if (!file_exists($filepath)) {
|
||||
throw new FileNotFoundException($filepath);
|
||||
}
|
||||
return $filepath;
|
||||
}
|
||||
|
||||
public function getUrl()
|
||||
public function getUrl($prefer_local=true)
|
||||
{
|
||||
if (!empty($this->filename)) {
|
||||
if ($prefer_local && !empty($this->filename)) {
|
||||
// A locally stored file, so let's generate a URL for our instance.
|
||||
$url = self::url($this->filename);
|
||||
if ($url != $this->url) {
|
||||
// For indexing purposes, in case we do a lookup on the 'url' field.
|
||||
// also we're fixing possible changes from http to https, or paths
|
||||
$this->updateUrl($url);
|
||||
}
|
||||
return $url;
|
||||
return self::url($this->filename);
|
||||
}
|
||||
|
||||
// No local filename available, return the URL we have stored
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
static public function getByUrl($url)
|
||||
{
|
||||
$file = new File();
|
||||
$file->urlhash = self::hashurl($url);
|
||||
if (!$file->find(true)) {
|
||||
throw new NoResultException($file);
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hashstr String of (preferrably lower case) hexadecimal characters, same as result of 'hash_file(...)'
|
||||
*/
|
||||
static public function getByHash($hashstr)
|
||||
{
|
||||
$file = new File();
|
||||
$file->filehash = strtolower($hashstr);
|
||||
if (!$file->find(true)) {
|
||||
throw new NoResultException($file);
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function updateUrl($url)
|
||||
{
|
||||
$file = File::getKV('url', $url);
|
||||
$file = File::getKV('urlhash', self::hashurl($url));
|
||||
if ($file instanceof File) {
|
||||
throw new ServerException('URL already exists in DB');
|
||||
}
|
||||
$sql = 'UPDATE %1$s SET url=%2$s WHERE url=%3$s;';
|
||||
$result = $this->query(sprintf($sql, $this->__table,
|
||||
$sql = 'UPDATE %1$s SET urlhash=%2$s, url=%3$s WHERE urlhash=%4$s;';
|
||||
$result = $this->query(sprintf($sql, $this->tableName(),
|
||||
$this->_quote((string)self::hashurl($url)),
|
||||
$this->_quote((string)$url),
|
||||
$this->_quote((string)$this->url)));
|
||||
$this->_quote((string)$this->urlhash)));
|
||||
if ($result === false) {
|
||||
common_log_db_error($this, 'UPDATE', __FILE__);
|
||||
throw new ServerException("Could not UPDATE {$this->__table}.url");
|
||||
throw new ServerException("Could not UPDATE {$this->tableName()}.url");
|
||||
}
|
||||
|
||||
return $result;
|
||||
@@ -502,9 +504,9 @@ class File extends Managed_DataObject
|
||||
|
||||
function blowCache($last=false)
|
||||
{
|
||||
self::blow('file:notice-ids:%s', $this->url);
|
||||
self::blow('file:notice-ids:%s', $this->id);
|
||||
if ($last) {
|
||||
self::blow('file:notice-ids:%s;last', $this->url);
|
||||
self::blow('file:notice-ids:%s;last', $this->id);
|
||||
}
|
||||
self::blow('file:notice-count:%d', $this->id);
|
||||
}
|
||||
@@ -570,6 +572,14 @@ class File extends Managed_DataObject
|
||||
$thumbs->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$f2p = new File_to_post();
|
||||
$f2p->file_id = $this->id;
|
||||
if ($f2p->find()) {
|
||||
while ($f2p->fetch()) {
|
||||
$f2p->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// And finally remove the entry from the database
|
||||
@@ -582,4 +592,87 @@ class File extends Managed_DataObject
|
||||
|
||||
return $title ?: null;
|
||||
}
|
||||
|
||||
static public function hashurl($url)
|
||||
{
|
||||
if (empty($url)) {
|
||||
throw new Exception('No URL provided to hash algorithm.');
|
||||
}
|
||||
return hash(self::URLHASH_ALG, $url);
|
||||
}
|
||||
|
||||
static public function beforeSchemaUpdate()
|
||||
{
|
||||
$table = strtolower(get_called_class());
|
||||
$schema = Schema::get();
|
||||
$schemadef = $schema->getTableDef($table);
|
||||
|
||||
// 2015-02-19 We have to upgrade our table definitions to have the urlhash field populated
|
||||
if (isset($schemadef['fields']['urlhash']) && isset($schemadef['unique keys']['file_urlhash_key'])) {
|
||||
// We already have the urlhash field, so no need to migrate it.
|
||||
return;
|
||||
}
|
||||
echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
|
||||
|
||||
$file = new File();
|
||||
$file->query(sprintf('SELECT id, LEFT(url, 191) AS shortenedurl, COUNT(*) AS c FROM %1$s WHERE LENGTH(url)>191 GROUP BY shortenedurl HAVING c > 1', $schema->quoteIdentifier($table)));
|
||||
print "\nFound {$file->N} URLs with too long entries in file table\n";
|
||||
while ($file->fetch()) {
|
||||
// We've got a URL that is too long for our future file table
|
||||
// so we'll cut it. We could save the original URL, but there is
|
||||
// no guarantee it is complete anyway since the previous max was 255 chars.
|
||||
$dupfile = new File();
|
||||
// First we find file entries that would be duplicates of this when shortened
|
||||
// ... and we'll just throw the dupes out the window for now! It's already so borken.
|
||||
$dupfile->query(sprintf('SELECT * FROM file WHERE LEFT(url, 191) = "%1$s"', $file->shortenedurl));
|
||||
// Leave one of the URLs in the database by using ->find(true) (fetches first entry)
|
||||
if ($dupfile->find(true)) {
|
||||
print "\nShortening url entry for $table id: {$file->id} [";
|
||||
$orig = clone($dupfile);
|
||||
$dupfile->url = $file->shortenedurl; // make sure it's only 191 chars from now on
|
||||
$dupfile->update($orig);
|
||||
print "\nDeleting duplicate entries of too long URL on $table id: {$file->id} [";
|
||||
// only start deleting with this fetch.
|
||||
while($dupfile->fetch()) {
|
||||
print ".";
|
||||
$dupfile->delete();
|
||||
}
|
||||
print "]\n";
|
||||
} else {
|
||||
print "\nWarning! URL suddenly disappeared from database: {$file->url}\n";
|
||||
}
|
||||
}
|
||||
echo "...and now all the non-duplicates which are longer than 191 characters...\n";
|
||||
$file->query('UPDATE file SET url=LEFT(url, 191) WHERE LENGTH(url)>191');
|
||||
|
||||
echo "\n...now running hacky pre-schemaupdate change for $table:";
|
||||
// We have to create a urlhash that is _not_ the primary key,
|
||||
// transfer data and THEN run checkSchema
|
||||
$schemadef['fields']['urlhash'] = array (
|
||||
'type' => 'varchar',
|
||||
'length' => 64,
|
||||
'not null' => false, // this is because when adding column, all entries will _be_ NULL!
|
||||
'description' => 'sha256 of destination URL (url field)',
|
||||
);
|
||||
$schemadef['fields']['url'] = array (
|
||||
'type' => 'text',
|
||||
'description' => 'destination URL after following possible redirections',
|
||||
);
|
||||
unset($schemadef['unique keys']);
|
||||
$schema->ensureTable($table, $schemadef);
|
||||
echo "DONE.\n";
|
||||
|
||||
$classname = ucfirst($table);
|
||||
$tablefix = new $classname;
|
||||
// urlhash is hash('sha256', $url) in the File table
|
||||
echo "Updating urlhash fields in $table table...";
|
||||
// Maybe very MySQL specific :(
|
||||
$tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;',
|
||||
$schema->quoteIdentifier($table),
|
||||
'urlhash',
|
||||
// The line below is "result of sha256 on column `url`"
|
||||
'SHA2(url, 256)'));
|
||||
echo "DONE.\n";
|
||||
echo "Resuming core schema upgrade...";
|
||||
}
|
||||
}
|
||||
|
||||
+165
-80
@@ -29,7 +29,8 @@ class File_redirection extends Managed_DataObject
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'file_redirection'; // table name
|
||||
public $url; // varchar(255) primary_key not_null
|
||||
public $urlhash; // varchar(64) primary_key not_null
|
||||
public $url; // text
|
||||
public $file_id; // int(4)
|
||||
public $redirections; // int(4)
|
||||
public $httpcode; // int(4)
|
||||
@@ -38,29 +39,37 @@ class File_redirection extends Managed_DataObject
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
protected $file; /* Cache the associated file sometimes */
|
||||
|
||||
public static function schemaDef()
|
||||
{
|
||||
return array(
|
||||
'fields' => array(
|
||||
'url' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'short URL (or any other kind of redirect) for file (id)'),
|
||||
'urlhash' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'sha256 hash of the URL'),
|
||||
'url' => array('type' => 'text', 'description' => 'short URL (or any other kind of redirect) for file (id)'),
|
||||
'file_id' => array('type' => 'int', 'description' => 'short URL for what URL/file'),
|
||||
'redirections' => array('type' => 'int', 'description' => 'redirect count'),
|
||||
'httpcode' => array('type' => 'int', 'description' => 'HTTP status code (20x, 30x, etc.)'),
|
||||
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
|
||||
),
|
||||
'primary key' => array('url'),
|
||||
'primary key' => array('urlhash'),
|
||||
'foreign keys' => array(
|
||||
'file_redirection_file_id_fkey' => array('file' => array('file_id' => 'id')),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static public function getByUrl($url)
|
||||
{
|
||||
return self::getByPK(array('urlhash' => File::hashurl($url)));
|
||||
}
|
||||
|
||||
static function _commonHttp($url, $redirs) {
|
||||
$request = new HTTPClient($url);
|
||||
$request->setConfig(array(
|
||||
'connect_timeout' => 10, // # seconds to wait
|
||||
'max_redirs' => $redirs, // # max number of http redirections to follow
|
||||
'follow_redirects' => true, // Follow redirects
|
||||
'follow_redirects' => false, // We follow redirects ourselves in lib/httpclient.php
|
||||
'store_body' => false, // We won't need body content here.
|
||||
));
|
||||
return $request;
|
||||
@@ -87,7 +96,7 @@ class File_redirection extends Managed_DataObject
|
||||
* size (optional): byte size from Content-Length header
|
||||
* time (optional): timestamp from Last-Modified header
|
||||
*/
|
||||
public function lookupWhere($short_url, $redirs = 10, $protected = false) {
|
||||
static function lookupWhere($short_url, $redirs = 10, $protected = false) {
|
||||
if ($redirs < 0) return false;
|
||||
|
||||
if(strpos($short_url,'://') === false){
|
||||
@@ -111,21 +120,26 @@ class File_redirection extends Managed_DataObject
|
||||
// no content it'll be cheap. :)
|
||||
$request = self::_commonHttp($short_url, $redirs);
|
||||
$response = $request->send();
|
||||
} elseif (400 == $response->getStatus()) {
|
||||
throw new Exception('Got error 400 on HEAD request, will not go further.');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Invalid URL or failure to reach server
|
||||
common_log(LOG_ERR, "Error while following redirects for $short_url: " . $e->getMessage());
|
||||
return $short_url;
|
||||
}
|
||||
|
||||
if ($response->getRedirectCount() && File::isProtected($response->getUrl())) {
|
||||
// Bump back up the redirect chain until we find a non-protected URL
|
||||
return self::lookupWhere($short_url, $response->getRedirectCount() - 1, true);
|
||||
|
||||
// if last url after all redirections is protected,
|
||||
// use the url before it in the redirection chain
|
||||
if ($response->getRedirectCount() && File::isProtected($response->getEffectiveUrl())) {
|
||||
$return_url = $response->redirUrls[$response->getRedirectCount()-1];
|
||||
} else {
|
||||
$return_url = $response->getEffectiveUrl();
|
||||
}
|
||||
|
||||
$ret = array('code' => $response->getStatus()
|
||||
, 'redirects' => $response->getRedirectCount()
|
||||
, 'url' => $response->getUrl());
|
||||
, 'url' => $return_url);
|
||||
|
||||
$type = $response->getHeader('Content-Type');
|
||||
if ($type) $ret['type'] = $type;
|
||||
@@ -148,40 +162,70 @@ class File_redirection extends Managed_DataObject
|
||||
*
|
||||
* @param string $in_url
|
||||
* @param boolean $discover true to attempt dereferencing the redirect if we don't know it already
|
||||
* @return mixed one of:
|
||||
* string - target URL, if this is a direct link or a known redirect
|
||||
* array - redirect info if this is an *unknown* redirect:
|
||||
* associative array with the following elements:
|
||||
* code: HTTP status code
|
||||
* redirects: count of redirects followed
|
||||
* url: URL string of final target
|
||||
* type (optional): MIME type from Content-Type header
|
||||
* size (optional): byte size from Content-Length header
|
||||
* time (optional): timestamp from Last-Modified header
|
||||
* @return File_redirection
|
||||
*/
|
||||
public function where($in_url, $discover=true) {
|
||||
// let's see if we know this...
|
||||
$a = File::getKV('url', $in_url);
|
||||
static function where($in_url, $discover=true) {
|
||||
$redir = new File_redirection();
|
||||
$redir->url = $in_url;
|
||||
$redir->urlhash = File::hashurl($redir->url);
|
||||
$redir->redirections = 0;
|
||||
|
||||
if (!empty($a)) {
|
||||
// this is a direct link to $a->url
|
||||
return $a->url;
|
||||
} else {
|
||||
$b = File_redirection::getKV('url', $in_url);
|
||||
if (!empty($b)) {
|
||||
// this is a redirect to $b->file_id
|
||||
$a = File::getKV('id', $b->file_id);
|
||||
return $a->url;
|
||||
try {
|
||||
$r = File_redirection::getByUrl($in_url);
|
||||
if($r instanceof File_redirection) {
|
||||
try {
|
||||
$f = File::getKV('id',$r->file_id);
|
||||
$r->file = $f;
|
||||
$r->redir_url = $f->url;
|
||||
} catch (NoResultException $e) {
|
||||
// Invalid entry, delete and run again
|
||||
common_log(LOG_ERR, "Could not find File with id=".$r->file_id." referenced in File_redirection, deleting File redirection entry and creating new File and File_redirection entries.");
|
||||
$r->delete();
|
||||
return self::where($in_url);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
} catch (NoResultException $e) {
|
||||
try {
|
||||
$f = File::getByUrl($in_url);
|
||||
$redir->file_id = $f->id;
|
||||
$redir->file = $f;
|
||||
return $redir;
|
||||
} catch (NoResultException $e) {
|
||||
// Oh well, let's keep going
|
||||
}
|
||||
}
|
||||
|
||||
if ($discover) {
|
||||
$ret = File_redirection::lookupWhere($in_url);
|
||||
return $ret;
|
||||
} else {
|
||||
// No manual dereferencing; leave the unknown URL as is.
|
||||
return $in_url;
|
||||
if ($discover) {
|
||||
$redir_info = File_redirection::lookupWhere($in_url);
|
||||
if(is_string($redir_info)) {
|
||||
$redir_info = array('url' => $redir_info);
|
||||
}
|
||||
|
||||
// Save the file if we don't have it already
|
||||
$redir->file = File::saveNew($redir_info,$redir_info['url']);
|
||||
|
||||
// If this is a redirection, save it
|
||||
// (if it hasn't been saved yet by some other process while we we
|
||||
// were running lookupWhere())
|
||||
if($redir_info['url'] != $in_url) {
|
||||
try {
|
||||
$file_redir = File_redirection::getByUrl($in_url);
|
||||
} catch (NoResultException $e) {
|
||||
$file_redir = new File_redirection();
|
||||
$file_redir->urlhash = File::hashurl($in_url);
|
||||
$file_redir->url = $in_url;
|
||||
$file_redir->file_id = $redir->file->getID();
|
||||
$file_redir->insert();
|
||||
$file_redir->redir_url = $redir->file->url;
|
||||
}
|
||||
|
||||
$file_redir->file = $redir->file;
|
||||
return $file_redir;
|
||||
}
|
||||
}
|
||||
|
||||
return $redir;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +242,7 @@ class File_redirection extends Managed_DataObject
|
||||
* @param User $user whose shortening options to use; defaults to the current web session user
|
||||
* @return string
|
||||
*/
|
||||
function makeShort($long_url, $user=null)
|
||||
static function makeShort($long_url, $user=null)
|
||||
{
|
||||
$canon = File_redirection::_canonUrl($long_url);
|
||||
|
||||
@@ -206,11 +250,7 @@ class File_redirection extends Managed_DataObject
|
||||
|
||||
// Did we get one? Is it shorter?
|
||||
|
||||
if (!empty($short_url)) {
|
||||
return $short_url;
|
||||
} else {
|
||||
return $long_url;
|
||||
}
|
||||
return !empty($short_url) ? $short_url : $long_url;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,55 +267,37 @@ class File_redirection extends Managed_DataObject
|
||||
* @return string
|
||||
*/
|
||||
|
||||
function forceShort($long_url, $user)
|
||||
static function forceShort($long_url, $user)
|
||||
{
|
||||
$canon = File_redirection::_canonUrl($long_url);
|
||||
|
||||
$short_url = File_redirection::_userMakeShort($canon, $user, true);
|
||||
|
||||
// Did we get one? Is it shorter?
|
||||
if (!empty($short_url)) {
|
||||
return $short_url;
|
||||
} else {
|
||||
return $long_url;
|
||||
}
|
||||
return !empty($short_url) ? $short_url : $long_url;
|
||||
}
|
||||
|
||||
function _userMakeShort($long_url, User $user=null, $force = false) {
|
||||
static function _userMakeShort($long_url, User $user=null, $force = false) {
|
||||
$short_url = common_shorten_url($long_url, $user, $force);
|
||||
if (!empty($short_url) && $short_url != $long_url) {
|
||||
$short_url = (string)$short_url;
|
||||
// store it
|
||||
$file = File::getKV('url', $long_url);
|
||||
if ($file instanceof File) {
|
||||
$file_id = $file->id;
|
||||
} else {
|
||||
try {
|
||||
$file = File::getByUrl($long_url);
|
||||
} catch (NoResultException $e) {
|
||||
// Check if the target URL is itself a redirect...
|
||||
$redir_data = File_redirection::where($long_url);
|
||||
if (is_array($redir_data)) {
|
||||
// We haven't seen the target URL before.
|
||||
// Save file and embedding data about it!
|
||||
$file = File::saveNew($redir_data, $long_url);
|
||||
$file_id = $file->id;
|
||||
} else if (is_string($redir_data)) {
|
||||
// The file is a known redirect target.
|
||||
$file = File::getKV('url', $redir_data);
|
||||
if (empty($file)) {
|
||||
// @fixme should we save a new one?
|
||||
// this case was triggering sometimes for redirects
|
||||
// with unresolvable targets; found while fixing
|
||||
// "can't linkify" bugs with shortened links to
|
||||
// SSL sites with cert issues.
|
||||
return null;
|
||||
}
|
||||
$file_id = $file->id;
|
||||
}
|
||||
// This should already have happened in processNew in common_shorten_url()
|
||||
$redir = File_redirection::where($long_url);
|
||||
$file = $redir->file;
|
||||
}
|
||||
$file_redir = File_redirection::getKV('url', $short_url);
|
||||
if (!$file_redir instanceof File_redirection) {
|
||||
$file_redir = new File_redirection;
|
||||
// Now we definitely have a File object in $file
|
||||
try {
|
||||
$file_redir = File_redirection::getByUrl($short_url);
|
||||
} catch (NoResultException $e) {
|
||||
$file_redir = new File_redirection();
|
||||
$file_redir->urlhash = File::hashurl($short_url);
|
||||
$file_redir->url = $short_url;
|
||||
$file_redir->file_id = $file_id;
|
||||
$file_redir->file_id = $file->getID();
|
||||
$file_redir->insert();
|
||||
}
|
||||
return $short_url;
|
||||
@@ -295,7 +317,7 @@ class File_redirection extends Managed_DataObject
|
||||
* @param string $default_scheme if given a bare link; defaults to 'http://'
|
||||
* @return string
|
||||
*/
|
||||
function _canonUrl($in_url, $default_scheme = 'http://') {
|
||||
static function _canonUrl($in_url, $default_scheme = 'http://') {
|
||||
if (empty($in_url)) return false;
|
||||
$out_url = $in_url;
|
||||
$p = parse_url($out_url);
|
||||
@@ -307,6 +329,8 @@ class File_redirection extends Managed_DataObject
|
||||
$out_url = str_replace('.-()', '', $out_url);
|
||||
break;
|
||||
|
||||
// non-HTTP schemes, so no redirects
|
||||
case 'bitcoin':
|
||||
case 'mailto':
|
||||
case 'aim':
|
||||
case 'jabber':
|
||||
@@ -314,6 +338,16 @@ class File_redirection extends Managed_DataObject
|
||||
// don't touch anything
|
||||
break;
|
||||
|
||||
// URLs without domain name, so no redirects
|
||||
case 'magnet':
|
||||
// don't touch anything
|
||||
break;
|
||||
|
||||
// URLs with coordinates, not browsable domain names
|
||||
case 'geo':
|
||||
// don't touch anything
|
||||
break;
|
||||
|
||||
default:
|
||||
$out_url = $default_scheme . ltrim($out_url, '/');
|
||||
$p = parse_url($out_url);
|
||||
@@ -332,12 +366,63 @@ class File_redirection extends Managed_DataObject
|
||||
return $out_url;
|
||||
}
|
||||
|
||||
function saveNew($data, $file_id, $url) {
|
||||
static function saveNew($data, $file_id, $url) {
|
||||
$file_redir = new File_redirection;
|
||||
$file_redir->urlhash = File::hashurl($url);
|
||||
$file_redir->url = $url;
|
||||
$file_redir->file_id = $file_id;
|
||||
$file_redir->redirections = intval($data['redirects']);
|
||||
$file_redir->httpcode = intval($data['code']);
|
||||
$file_redir->insert();
|
||||
}
|
||||
|
||||
static public function beforeSchemaUpdate()
|
||||
{
|
||||
$table = strtolower(get_called_class());
|
||||
$schema = Schema::get();
|
||||
$schemadef = $schema->getTableDef($table);
|
||||
|
||||
// 2015-02-19 We have to upgrade our table definitions to have the urlhash field populated
|
||||
if (isset($schemadef['fields']['urlhash']) && in_array('urlhash', $schemadef['primary key'])) {
|
||||
// We already have the urlhash field, so no need to migrate it.
|
||||
return;
|
||||
}
|
||||
echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
|
||||
// We have to create a urlhash that is _not_ the primary key,
|
||||
// transfer data and THEN run checkSchema
|
||||
$schemadef['fields']['urlhash'] = array (
|
||||
'type' => 'varchar',
|
||||
'length' => 64,
|
||||
'not null' => true,
|
||||
'description' => 'sha256 hash of the URL',
|
||||
);
|
||||
$schemadef['fields']['url'] = array (
|
||||
'type' => 'text',
|
||||
'description' => 'short URL (or any other kind of redirect) for file (id)',
|
||||
);
|
||||
unset($schemadef['primary key']);
|
||||
$schema->ensureTable($table, $schemadef);
|
||||
echo "DONE.\n";
|
||||
|
||||
$classname = ucfirst($table);
|
||||
$tablefix = new $classname;
|
||||
// urlhash is hash('sha256', $url) in the File table
|
||||
echo "Updating urlhash fields in $table table...";
|
||||
// Maybe very MySQL specific :(
|
||||
$tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;',
|
||||
$schema->quoteIdentifier($table),
|
||||
'urlhash',
|
||||
// The line below is "result of sha256 on column `url`"
|
||||
'SHA2(url, 256)'));
|
||||
echo "DONE.\n";
|
||||
echo "Resuming core schema upgrade...";
|
||||
}
|
||||
|
||||
public function getFile() {
|
||||
if(empty($this->file) && $this->file_id) {
|
||||
$this->file = File::getKV('id', $this->file_id);
|
||||
}
|
||||
|
||||
return $this->file;
|
||||
}
|
||||
}
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário