Comparar commits
725 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| d4fa67cc8e | |||
| 51740e4d49 | |||
| 474376938b | |||
| 440cd110ed | |||
| 018f5fbfde | |||
| d7ab9cd72e | |||
| 510b6c5f9c | |||
| 0b152b2c24 | |||
| af404f4a15 | |||
| 40b38c5b11 | |||
| a4e08c43d2 | |||
| 495b497a1c | |||
| 57a38b81df | |||
| 195b7e4508 | |||
| 302d065fcd | |||
| a2d28b29b8 | |||
| 3d447e43e8 | |||
| b9877c8b93 | |||
| 82a1c6e992 | |||
| aedafdf6fe | |||
| c6d1296cd7 | |||
| 236ac4b09f | |||
| 6b1fe66810 | |||
| e6b2abbe49 | |||
| 52a213a707 | |||
| f1f108a569 | |||
| e3a0e6b5c8 | |||
| 7393c06302 | |||
| 51625e8397 | |||
| 03cbedb255 | |||
| 8f7892c0c0 | |||
| 632d5f1136 | |||
| b32ce177f8 | |||
| 52beccf1ac | |||
| 9214aaf541 | |||
| 4c8bc04bca | |||
| e83d89e99d | |||
| e033e37c05 | |||
| d3c3112310 | |||
| c43d50e59f | |||
| 7798a3dfcc | |||
| 0632ce2125 | |||
| 34510bcf37 | |||
| 48a0414a60 | |||
| 1d4ae5a030 | |||
| 2ecf1b4f5d | |||
| 182f1671e9 | |||
| 05c4f15438 | |||
| 6731c8d8bf | |||
| 1db306b6e7 | |||
| bfa61fde2c | |||
| 5202fda5c8 | |||
| eccef8b103 | |||
| 21951743d4 | |||
| 1336625bd0 | |||
| 649b3dde42 | |||
| a969a6beb1 | |||
| beaba40458 | |||
| be7a837952 | |||
| 4ae1cb69d0 | |||
| e9640d2571 | |||
| 0ede7af280 | |||
| 77e8f563d1 | |||
| 3a71ec89ca | |||
| e933ff9510 | |||
| 551a1079d2 | |||
| c45a40dea3 | |||
| 7018d0979d | |||
| f887c95d63 | |||
| 9dec96f20e | |||
| 7986be86fa | |||
| 8d329c29fd | |||
| 8a3043090a | |||
| 0c178b5f2c | |||
| cb97446c20 | |||
| 13213d1086 | |||
| b2264c2e7a | |||
| 0bf871e8e8 | |||
| 3e90377125 | |||
| e53e866b3f | |||
| 7120eb531d | |||
| f3a762388c | |||
| 3f1702e73e | |||
| 220d54f199 | |||
| d0d54dac15 | |||
| f03904a1e3 | |||
| 88d8a8c1af | |||
| 0273158e47 | |||
| 69f00546f7 | |||
| d1f04b3b9a | |||
| e5f22390dc | |||
| df49cd0d81 | |||
| 9d81edfc67 | |||
| b95e2a821a | |||
| 46841df539 | |||
| bcde8938b8 | |||
| 72a21c07b0 | |||
| ab46159b5c | |||
| ab7cdc0b1f | |||
| 0edcf5764c | |||
| 82da438dfb | |||
| 6f732e3839 | |||
| 72c7b97c38 | |||
| 11e177e724 | |||
| c14a78a40a | |||
| a860b5c1eb | |||
| 351a1fc461 | |||
| e321f40a64 | |||
| 6494335e79 | |||
| 6ecf09bf5c | |||
| a743c6994e | |||
| be1d393706 | |||
| 17a2b7d7ee | |||
| 84550f6d95 | |||
| db3ffd5249 | |||
| aac20dab52 | |||
| e9df9b7bdb | |||
| 05825ecc93 | |||
| afb3c6450d | |||
| 68b3d377e8 | |||
| cafa618671 | |||
| e224d98593 | |||
| 2dbd6c539c | |||
| 0e0a92638f | |||
| 3bbfabfd4b | |||
| 04eefb7836 | |||
| 6f7370ad4b | |||
| 9bf92d11aa | |||
| 4d5b8e2907 | |||
| 40eed77d50 | |||
| 974d964905 | |||
| d87cc71034 | |||
| 34b25e032e | |||
| 56e55bb253 | |||
| 9139b33bb4 | |||
| 08a35313a1 | |||
| 1f0e63cfa8 | |||
| db30b4487b | |||
| 3199c944c0 | |||
| e468470fd2 | |||
| 7e33c337cb | |||
| a1902a221e | |||
| 4898445d62 | |||
| eff168e70f | |||
| 049049d8bf | |||
| c3aed808ba | |||
| bab2335cd9 | |||
| fbc5cdfba5 | |||
| 876b15a5cd | |||
| 9f24af8a02 | |||
| e6a8cad494 | |||
| 75aec590ca | |||
| 363de485f4 | |||
| e9d4634fb0 | |||
| 9271c4e5f0 | |||
| 80a8ad5f30 | |||
| 1d63aa14f0 | |||
| 5dc4b74fb7 | |||
| f2a6bbf685 | |||
| ec8204794e | |||
| 09b7d070f6 | |||
| 154614322a | |||
| 11186c14b8 | |||
| fcd41e8c2b | |||
| 2570877580 | |||
| a2a38680a3 | |||
| 131f9a673d | |||
| f977f9ba8a | |||
| 4592c65939 | |||
| 11d79dbee9 | |||
| 35f6515cab | |||
| b1852c79c0 | |||
| 4898d83fe8 | |||
| a6fbae5938 | |||
| b3200f993a | |||
| a4661e15eb | |||
| 0f9ec45a06 | |||
| 4be6c25996 | |||
| 1e57eba7d1 | |||
| 5675069b6b | |||
| f8e93650e8 | |||
| 8dc071c955 | |||
| f82589398b | |||
| 2c66b7e39c | |||
| de078b42b5 | |||
| 2dbcda40b1 | |||
| 0e99f04c43 | |||
| 0bc9d2cd26 | |||
| 3b3ddbe83d | |||
| a5d114cd0c | |||
| 92611273c3 | |||
| b442f365a1 | |||
| 2a75c0b31c | |||
| d58a88d54d | |||
| baa8d224d7 | |||
| 970bfb4090 | |||
| f5acc4a386 | |||
| bdc9eb8aae | |||
| 72d19b1e14 | |||
| 89de83b103 | |||
| dc7cdeb4f9 | |||
| 3ab4b1cdb6 | |||
| 2816507545 | |||
| aa828e620c | |||
| 596b4b8e02 | |||
| 45b50d3387 | |||
| fda1da319f | |||
| 6f6a593984 | |||
| 086991fab8 | |||
| 6909aea0ba | |||
| 6023bf8a87 | |||
| 9eed5c6ed8 | |||
| 6ebae1f2f0 | |||
| e1c8080e8f | |||
| d9a1351036 | |||
| 22559c314a | |||
| 9d0d8df2d6 | |||
| b3eef26174 | |||
| e8f2668879 | |||
| 14b524f0ac | |||
| a855c98834 | |||
| 0ca69fab72 | |||
| 2baf5bde07 | |||
| dc0747bc39 | |||
| 3037794b6d | |||
| d2a81a6f9c | |||
| 130febadf7 | |||
| cc5739918e | |||
| 23ecdf2a07 | |||
| 9db1d67fca | |||
| a0bd41d9f7 | |||
| 182ae843ca | |||
| 13256d2a66 | |||
| 3e7ce55384 | |||
| 2b8065e047 | |||
| 93cfed124f | |||
| fabdad7dc7 | |||
| 7df7eb1aeb | |||
| 97fa39126b | |||
| c60d1101f9 | |||
| 2590528d63 | |||
| 6d3a8695bb | |||
| 296df6357d | |||
| 60acc52638 | |||
| b4f45b8537 | |||
| 077a5a04a2 | |||
| 4c6a860bae | |||
| f722720cc3 | |||
| c01906055e | |||
| 8abbdeb3c0 | |||
| 949162b258 | |||
| d247c08aeb | |||
| 7285e3a8b4 | |||
| 4c0f42984c | |||
| e1554be53b | |||
| 55bfc12a1b | |||
| 9714829ec9 | |||
| c10c4d1a2f | |||
| ef25c8484c | |||
| 352ab5bc75 | |||
| 06cdb7f1c1 | |||
| 70a3600da2 | |||
| 7d4ed44ff9 | |||
| d2a8a8fb0b | |||
| 2d6ad4db65 | |||
| 7120531ba2 | |||
| 1b7a9c507b | |||
| b957114ad2 | |||
| e49964458c | |||
| 78c6577c54 | |||
| 65c5d4caca | |||
| b7b842def9 | |||
| ab6b07dad3 | |||
| f6fbda7b81 | |||
| ded4c6aceb | |||
| 094ed63c17 | |||
| 19db6dd8fe | |||
| 2994d86045 | |||
| 0353003038 | |||
| afd3fceeee | |||
| c90f2026ab | |||
| ed3d8af57b | |||
| 2610a52566 | |||
| cb635d6e04 | |||
| c2ff567339 | |||
| 30fc0b2d3b | |||
| 087ef6cf95 | |||
| 2fec0c5cd1 | |||
| a47ea60100 | |||
| 889305d8eb | |||
| 81729b9646 | |||
| 182615a9d9 | |||
| 94d00b7a86 | |||
| 8907798e4d | |||
| afa579be1c | |||
| 7fb4f27850 | |||
| fd2d7555b3 | |||
| 755f3a78b7 | |||
| 1b722228d2 | |||
| e897cb5cb8 | |||
| 4620585694 | |||
| 31bd84305d | |||
| 9efd552de6 | |||
| bb2837fe2b | |||
| 8093f6d9b6 | |||
| 2a9d45dba3 | |||
| 92c289f4d6 | |||
| 0383ca698a | |||
| 5ce6bb698f | |||
| 2348f803f2 | |||
| 49a453b631 | |||
| b6213f356c | |||
| 5efe3e834e | |||
| 5101cf22b2 | |||
| d913d9a3b8 | |||
| 93f0413669 | |||
| b7bdb7335a | |||
| 8168f40764 | |||
| 938c2d4082 | |||
| bd2440cf2d | |||
| 7293db4dc2 | |||
| 9a34cd7ea6 | |||
| f11fb22aaa | |||
| 4ccb691e15 | |||
| 3d6b6f00dc | |||
| 8eb374ac2c | |||
| 0fe484d7db | |||
| 22bd622bee | |||
| 98f831dd20 | |||
| eb3a2af822 | |||
| 607c309d4a | |||
| 5510b7d622 | |||
| c10d20a138 | |||
| 8a7f7ce368 | |||
| 3b39b3fc43 | |||
| 51b25f4a2b | |||
| 11df93fcb5 | |||
| d614b9fca8 | |||
| ba1816a6fd | |||
| 1b00c75700 | |||
| c44f7f4f41 | |||
| 965f40dc93 | |||
| 960c98429c | |||
| bcb88e5239 | |||
| 830ef883e0 | |||
| 3cc2eb3f14 | |||
| 74c52babc2 | |||
| f5f26a0145 | |||
| 33bf3e2912 | |||
| 95838ace25 | |||
| 35aad6a531 | |||
| e6e5eef247 | |||
| 710c53c8f1 | |||
| 7ad39a5315 | |||
| 89110d38f5 | |||
| 5319fe4359 | |||
| 6b778feb31 | |||
| e43b9359fc | |||
| 05bdb531a0 | |||
| 734bff0946 | |||
| 79288b3200 | |||
| 42740518d3 | |||
| 6e10461632 | |||
| 48f5cb0c8b | |||
| 74950a5325 | |||
| aaf93bce01 | |||
| 72508f8e5a | |||
| eb10b4c906 | |||
| 977faaade3 | |||
| a2102eadd1 | |||
| 47ce68a47e | |||
| 14e2a06317 | |||
| cc950a4cf0 | |||
| 3c6243ac50 | |||
| 34519017ac | |||
| 369fabef09 | |||
| 7554706792 | |||
| 62817126a4 | |||
| 5baaa38a78 | |||
| 37d94defdd | |||
| bd0e6ee357 | |||
| 416147dd81 | |||
| 1a8cb88014 | |||
| 1eceb0888a | |||
| 679d2995a5 | |||
| 64ccb1dc84 | |||
| 74931d584a | |||
| 3f9143870c | |||
| f0786ee8fe | |||
| ebaee73b03 | |||
| 0cc7d522c4 | |||
| f3f52a3202 | |||
| 02eced7291 | |||
| 1e81480f9b | |||
| 40edfae0a2 | |||
| 227d15b739 | |||
| 99f6e0eda9 | |||
| 28f9fb20c4 | |||
| 3a84d53242 | |||
| b11d690e9f | |||
| 44815db8d0 | |||
| 7534937fb7 | |||
| 71e9014bcd | |||
| 7fc8daac3b | |||
| ffbeaf309c | |||
| 4b66bcfe04 | |||
| 73a77a02fb | |||
| 8e210301cd | |||
| cc71314cdb | |||
| 10b5e76295 | |||
| 29b5b316f3 | |||
| 962c592e80 | |||
| d54da897e4 | |||
| 846b051ec4 | |||
| 62d2bbaaeb | |||
| f8ac716d67 | |||
| 0122cc658a | |||
| 3be72241c4 | |||
| fb0549693d | |||
| 072c411ac2 | |||
| c4ab6dec2e | |||
| b87d074de0 | |||
| 7b6acc3a64 | |||
| 1473e1e107 | |||
| 9d4ee91d38 | |||
| f3e9941bf0 | |||
| 78a43d3f4f | |||
| 598b619037 | |||
| ae24576fe7 | |||
| cff9c53f78 | |||
| f3161ec32f | |||
| 527b4ec86d | |||
| 65ca7bce0d | |||
| 8e001e3708 | |||
| 3ffc3a445e | |||
| 989beec472 | |||
| 5b041780df | |||
| 4a70176da0 | |||
| 14ae286aeb | |||
| 25447c2527 | |||
| 81c635d5f7 | |||
| 0e7a2d2673 | |||
| 5ed9d729ea | |||
| fd43133f0f | |||
| 560b71d93b | |||
| b57857b1bb | |||
| 70c0eb72dc | |||
| 8a71ee5b7e | |||
| 0224f12e88 | |||
| 3ae8005f01 | |||
| 32acfb9c01 | |||
| 791a9bc3d9 | |||
| 4e97088963 | |||
| 35dfe90942 | |||
| b9748f90aa | |||
| 789c397ddc | |||
| 8a76a28a66 | |||
| 2ffe165d41 | |||
| fefe9f2b87 | |||
| 819504224b | |||
| 99a0350cd7 | |||
| 111f57a269 | |||
| 6cd14881a0 | |||
| b85621c76a | |||
| 132d0d8966 | |||
| cf576c939a | |||
| 8fd44ec71e | |||
| 4a4c2aff0d | |||
| f893eb6dab | |||
| b12bad0ebd | |||
| 37f49588ef | |||
| e4cf072027 | |||
| 9d91ddfa22 | |||
| d49f753e62 | |||
| d016b0e64c | |||
| ecd4d56be0 | |||
| 1218512b4a | |||
| a5633f9cab | |||
| 5f3697c235 | |||
| d76f4e90bc | |||
| 885ca8b801 | |||
| 76f579b84a | |||
| 5c00ecc52c | |||
| 61f45d5163 | |||
| caa90568b2 | |||
| 09dacaffe9 | |||
| 11bdbcea2d | |||
| 885c5888a6 | |||
| c493e23d32 | |||
| b8a92b3ba9 | |||
| 3836a5cbad | |||
| ca80144ab0 | |||
| 80edef7b2c | |||
| 390dbc187e | |||
| f2b91357bd | |||
| f986c79c4f | |||
| daf4df9183 | |||
| f3ab18ffda | |||
| e1ad4f28f9 | |||
| 89a47856f0 | |||
| 68f1ae1929 | |||
| 4477ed8eb0 | |||
| c0d23598ef | |||
| 996d55e783 | |||
| 17d855a5da | |||
| 66f4ee92d8 | |||
| ca6ff275ff | |||
| cba85a12f7 | |||
| f2efe7bb32 | |||
| e97bbd2df5 | |||
| 4abe665c4b | |||
| 022a76d2dc | |||
| 96e718a5c3 | |||
| 9b6db57d66 | |||
| 66728fb136 | |||
| 6149e736d7 | |||
| 5ce4604b61 | |||
| dc5dcc6cf8 | |||
| 71d392e4e0 | |||
| 3825d0af5f | |||
| e8c66d9ce3 | |||
| 6fdc5568c5 | |||
| 9009133199 | |||
| ded70bec07 | |||
| 903ca469a9 | |||
| 21de93375f | |||
| bf0c0fcbc9 | |||
| d8abe400a7 | |||
| dcd4f55c69 | |||
| d35368039c | |||
| 71f4e82ac8 | |||
| 66124e5fa0 | |||
| ce79f407ea | |||
| ad2af23220 | |||
| 31498c6735 | |||
| 7dd784b77e | |||
| 9d323a6dde | |||
| ae5ccea547 | |||
| 2e4a8923ef | |||
| 1ba3c6bd29 | |||
| df99f9bbaa | |||
| c22eaa9f1b | |||
| 3de43b6b33 | |||
| 69e29469a3 | |||
| 3eebbb34ef | |||
| d6a023d4a5 | |||
| 22b720b08f | |||
| 8476807aaf | |||
| fff8844799 | |||
| cb7df0eead | |||
| 3754ef5b3d | |||
| 018d1d1bbb | |||
| 76dcc86ffc | |||
| fff77da69c | |||
| 08df7d8280 | |||
| 5a096a1a53 | |||
| 9965c42ab4 | |||
| 89b82becf4 | |||
| 721cb83201 | |||
| d9c978e5fa | |||
| 45b0019750 | |||
| 976be81ce9 | |||
| 4584a03ffe | |||
| e0bd1dc586 | |||
| 88c076ad11 | |||
| 3a7f8ab84d | |||
| dc189e1662 | |||
| 8966dd61f5 | |||
| 8fd507edcf | |||
| b4104b6635 | |||
| 2142f290f3 | |||
| c8769aa9f3 | |||
| 3be4017f85 | |||
| 17a2fc460c | |||
| 3e368e417e | |||
| c77d3840ee | |||
| 369b315889 | |||
| 9e12263ff5 | |||
| 1c3c8e306d | |||
| c5285189ae | |||
| 4485bbd2c6 | |||
| efa8a47652 | |||
| 8c817d0979 | |||
| 1f1b7804d7 | |||
| f465a8aea7 | |||
| 77f1b9d374 | |||
| 0e2b521d6e | |||
| 916fb82d65 | |||
| fbd081ecc5 | |||
| 37a30cbe5c | |||
| 4d67a4534a | |||
| 840a72dec7 | |||
| 04c242450d | |||
| 2a4d5f927c | |||
| f1ba999006 | |||
| f099e37d13 | |||
| db42f1186f | |||
| 5f24802df0 | |||
| a255b9fba6 | |||
| bf3178d799 | |||
| 2f1af5a59b | |||
| 51cda6f1da | |||
| 68e20d9ff1 | |||
| 1746928089 | |||
| b905b2fafb | |||
| 4a885bb495 | |||
| 926ce9564c | |||
| 430bfe3c54 | |||
| bdf669e2ed | |||
| c2365bd7db | |||
| 873c6584ad | |||
| 25874dd4c0 | |||
| 98edcc945c | |||
| 3097953589 | |||
| 0d9ed315eb | |||
| 5eb355ea67 | |||
| 8d83629823 | |||
| 44a3225cac | |||
| 393cef75b6 | |||
| 2143afd35f | |||
| 20dbc02e58 | |||
| 01461be17f | |||
| b1b0971576 | |||
| f0405de2e4 | |||
| 1001475f76 | |||
| 972f37cd7f | |||
| 0c79026f77 | |||
| 871fab52b9 | |||
| 9bf09b7f6d | |||
| 18536da247 | |||
| 8559bac6e2 | |||
| a13ccd7ca1 | |||
| e3da8af8e2 | |||
| 9984cf2911 | |||
| 8ac7cfdb17 | |||
| 32930233c4 | |||
| b3b030a143 | |||
| 42200dca19 | |||
| 1f70cfd5ad | |||
| 1c8d539237 | |||
| 5c0388a140 | |||
| eee1084be4 | |||
| e1695c5dba | |||
| 1e00226c7b | |||
| ddf7347f5d | |||
| a495d8e448 | |||
| f064b8c2ca | |||
| 1dc8606afc | |||
| 205d0bc40c | |||
| 354f886304 | |||
| 3ae48214cd | |||
| 4153f65587 | |||
| 063848360a | |||
| c7c1872076 | |||
| 9aa8c5f0a1 | |||
| 25c6c9261c | |||
| 95b117a249 | |||
| e4d4f3c3de | |||
| fdda2e4e0d | |||
| 80b9ca7fec | |||
| 492da05663 | |||
| 893462143a | |||
| 4610d596d9 | |||
| ca32b42165 | |||
| c9b2a50c64 | |||
| b94c24c930 | |||
| d4e1701e45 | |||
| 82c96b6380 | |||
| c1ebed7d64 | |||
| dd3b25bf2e | |||
| bd5986fe32 | |||
| 5a4ba6f14e | |||
| 090a2e70c6 | |||
| 2fe833c164 | |||
| 84ddb07130 | |||
| f1f58ac65f | |||
| 216750e084 | |||
| 113f7d04a7 | |||
| 92dace9f2a | |||
| 18877f77f0 | |||
| 8443b37035 | |||
| 7e9257635b | |||
| 62a546a1c1 | |||
| c95be84e60 | |||
| f0aff8cb97 | |||
| fdb2c5b49f | |||
| dd14e3977e | |||
| 0c5d8b9e43 | |||
| 871f0b6382 | |||
| 5c0733eba1 | |||
| b292a273d8 | |||
| 3d7113bf62 | |||
| f4d565c282 | |||
| c36100d9df | |||
| 2ff0f8ac7b | |||
| c0e1327288 | |||
| f9a683f8a1 | |||
| 2a57bbaf84 | |||
| acfed2353c | |||
| 9e45bcab47 | |||
| d079f94936 | |||
| d1af138974 | |||
| ddddbfd87d | |||
| d749713ef3 | |||
| a017ad1940 | |||
| e2b7ec3b23 | |||
| d1005c67a9 | |||
| 48baf874dc | |||
| cc989fae6e | |||
| 150bb1b9d6 | |||
| 4a069e1b13 | |||
| d9385c68bd | |||
| 60e6345c13 | |||
| 2c24b705de | |||
| 2843606a83 | |||
| e4f8d27937 | |||
| 2cabb47269 | |||
| d69453f846 | |||
| d5a3c0f003 | |||
| c4683bb3ba | |||
| 4677503011 | |||
| a016241dea | |||
| a6618b8dcc | |||
| b3f890053e | |||
| ce0100ee1e |
@@ -2,49 +2,39 @@ Qvitter
|
||||
==========================================
|
||||
|
||||
* Author: Hannes Mannerheim (<h@nnesmannerhe.im>)
|
||||
* Last mod.: May, 2015
|
||||
* Version: 4
|
||||
* GitHub: <https://github.com/hannesmannerheim/qvitter>
|
||||
* Last mod.: Jan, 2016
|
||||
* Version: 5-alpha
|
||||
* Homepage: <https://git.gnu.io/h2p/Qvitter>
|
||||
|
||||
Qvitter 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 three of the License or (at
|
||||
your option) any later version.
|
||||
|
||||
your option) any later version.
|
||||
|
||||
Qvitter is distributed in hope that it will be useful but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
more details.
|
||||
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Qvitter. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
along with Qvitter. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
1. Install GNU social
|
||||
1. Install GNU social _directly under a domain_ (Qvitter is not compatible with
|
||||
subdirectory installs) with _fancy urls_ enabled (if your instance has
|
||||
"index.php" in its URLs, Qvitter will not work properly) _and HTTPS enabled_ (it's
|
||||
always best to use HTTPS from the beginning, there will be issues with federation
|
||||
if you choose to enable HTTPS later)
|
||||
|
||||
2. Put all files in /plugins/Qvitter
|
||||
2. Put all files in local/plugins/Qvitter
|
||||
|
||||
3. Replace your lib/apiauthaction.php file with the one supplied in
|
||||
edited-gnu-social-files/lib/apiauthaction.php. (this might not be needed if you are
|
||||
running the latest GNU social nightly)
|
||||
3. Add `addPlugin('Qvitter');` to your /config.php file.
|
||||
|
||||
4. Add `addPlugin('Qvitter');` to your /config.php file.
|
||||
4. It's highly recommended to use the StoreRemoteMedia plugin. It will cache attachments from remote instances locally and make them appear in the streams. Add `addPlugin('StoreRemoteMedia');` to your /config.php file. (Only available in newer GNU social)
|
||||
|
||||
5. It's recommended to set this setting in your /config.php file: `$config['thumbnail']['maxsize'] = 3000;`
|
||||
|
||||
6. There are a few settings in /plugins/Qvitter/QvitterPlugin.php. By default Qvitter is
|
||||
opt-out for users. If you set `$settings['enabledbydefault'] = false;` Qvitter will
|
||||
be opt-in instead.
|
||||
|
||||
7. Users can go to ://{instance}/settings/qvitter and enable or disable Qvitter.
|
||||
|
||||
Optional
|
||||
-----
|
||||
|
||||
For easy updates, you can use /config.php to override the settings in /plugins/Qvitter/QvitterPlugin.php.
|
||||
For example, add this to your /config.php file:
|
||||
5. There are settings in QvitterPlugin.php, but for easy updates, put them in config.php instead. Example:
|
||||
|
||||
````
|
||||
// Qvitter-settings
|
||||
@@ -52,13 +42,53 @@ $config['site']['qvitter']['enabledbydefault'] = true;
|
||||
$config['site']['qvitter']['defaultbackgroundcolor'] = '#f4f4f4';
|
||||
$config['site']['qvitter']['defaultlinkcolor'] = '#0084B4';
|
||||
$config['site']['qvitter']['timebetweenpolling'] = 5000;
|
||||
$config['site']['qvitter']['urlshortenerapiurl'] = 'http://qttr.at/yourls-api.php';
|
||||
$config['site']['qvitter']['urlshortenersignature'] = 'b6afeec983';
|
||||
$config['site']['qvitter']['urlshortenerapiurl'] = 'http://qttr.at/yourls-api.php'; // if your site is on HTTPS, use url to shortener.php here
|
||||
$config['site']['qvitter']['urlshortenersignature'] = 'b6afeec983';
|
||||
$config['site']['qvitter']['sitebackground'] = 'img/vagnsmossen.jpg';
|
||||
$config['site']['qvitter']['favicon'] = 'img/favicon.ico?v=4';
|
||||
$config['site']['qvitter']['favicon_path'] = Plugin::staticPath('Qvitter', '').'img/gnusocial-favicons/';
|
||||
$config['site']['qvitter']['sprite'] = Plugin::staticPath('Qvitter', '').'img/sprite.png?v=40';
|
||||
$config['site']['qvitter']['enablewelcometext'] = true;
|
||||
// $config['site']['qvitter']['customwelcometext']['sv'] = '<h1>Välkommen till Quitter.se – en federerad<sup>1</sup> mikrobloggsallmänning!</h1><p>Etc etc...</p>';
|
||||
// $config['site']['qvitter']['customwelcometext']['en'] = '<h1>Welcome to Quitter.se – a federated microblog common!</h1><p>Etc etc...</p>';
|
||||
// $config['site']['qvitter']['customtermsofuse'] = 'Our custom terms of use';
|
||||
$config['site']['qvitter']['blocked_ips'] = array();
|
||||
$config['thumbnail']['maxsize'] = 3000;
|
||||
|
||||
// Recommended GNU social settings
|
||||
$config['thumbnail']['maxsize'] = 3000; // recommended setting to get more high-res image previews
|
||||
$config['profile']['delete'] = true; // twitter users are used to being able to remove their accounts
|
||||
$config['profile']['changenick'] = true; // twitter users are used to being able to change their nicknames
|
||||
$config['public']['localonly'] = true; // only local users in the public timeline (qvitter always has a timeline for the whole known network)
|
||||
addPlugin('StoreRemoteMedia'); // makes remote images appear in the feed
|
||||
|
||||
````
|
||||
|
||||
Note: This version of Qvitter is tested with GNU social version 1.1.1-alpha2 (7e47026085fa4f2071e694d9c3e3fe2aa5142135).
|
||||
The settings should be self-explanatory. In doubt, ask in the !qvitter group on quitter.se, or email h@nnesmannerhe.im
|
||||
|
||||
6. For better performance, disable checkschema (instructions in GNU social's config.php),
|
||||
but don't forget to run it when updating plugins (including Qvitter).
|
||||
|
||||
7. To change the logo, edit /img/sprite.png. For easier git-updates, put it in GNU social's locale folder, and edit the sprite path setting above.
|
||||
|
||||
|
||||
Translation
|
||||
-----
|
||||
|
||||
1. Translation files reside in /locale and /doc folders.
|
||||
|
||||
2. When translating .json files, don't translate the placeholder strings inside curly brackets {}
|
||||
|
||||
API
|
||||
-----
|
||||
|
||||
Qvitter uses GNU social's built in "twitter compatible" API. The API was designed to be
|
||||
compatible with Twitter's API v1.0. Some documentation is here: <http://skilledtests.com/wiki/Twitter-compatible_API>
|
||||
Twitter's API v1.1 documentation is also useful, but may be partly incorrect.
|
||||
|
||||
Qvitter extends this API in a few undocumented ways. See onRouterInitialized() in QvitterPlugin.php
|
||||
for ideas about paths for the API extensions.
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Qvitter is tested with the latest GNU social nightly
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Update the profile banner ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class ApiAccountUpdateProfileBannerAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
$this->cropW = $this->trimmed('width');
|
||||
$this->cropH = $this->trimmed('height');
|
||||
$this->cropX = $this->trimmed('offset_left');
|
||||
$this->cropY = $this->trimmed('offset_top');
|
||||
$this->img = $this->trimmed('banner');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// see if we have regular uploaded image data
|
||||
try {
|
||||
|
||||
$mediafile = MediaFile::fromUpload('banner', $this->scoped);
|
||||
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
|
||||
// if not we may have base64 data
|
||||
|
||||
$this->img = str_replace('data:image/jpeg;base64,', '', $this->img);
|
||||
$this->img = str_replace('data:image/png;base64,', '', $this->img);
|
||||
$this->img = str_replace(' ', '+', $this->img);
|
||||
$this->img = base64_decode($this->img, true);
|
||||
|
||||
$fh = tmpfile();
|
||||
fwrite($fh, $this->img);
|
||||
unset($this->img);
|
||||
fseek($fh, 0);
|
||||
|
||||
$mediafile = MediaFile::fromFilehandle($fh, $this->scoped);
|
||||
}
|
||||
|
||||
// maybe resize
|
||||
$width = $this->cropW;
|
||||
$height = $this->cropH;
|
||||
$scale = 1;
|
||||
if($width > 1200) {
|
||||
$scale = 1200/$width;
|
||||
} elseif($height > 600) {
|
||||
$scale = 600/$height;
|
||||
}
|
||||
$width = round($width*$scale);
|
||||
$height = round($height*$scale);
|
||||
|
||||
// crop
|
||||
try {
|
||||
$imagefile = ImageFile::fromFileObject($mediafile->fileRecord);
|
||||
unset($mediafile);
|
||||
|
||||
// We're just using the Avatar function to build a filename here
|
||||
// but we don't save it _as_ an avatar below... but in the same dir!
|
||||
$filename = Avatar::filename(
|
||||
$this->scoped->getID(),
|
||||
image_type_to_extension($imagefile->preferredType()),
|
||||
null,
|
||||
'banner-'.common_timestamp()
|
||||
);
|
||||
|
||||
$imagefile->resizeTo(Avatar::path($filename), array('width'=>$width, 'height'=>$height, 'x'=>$this->cropX, 'y'=>$this->cropY, 'w'=>$this->cropW, 'h'=>$this->cropH));
|
||||
$result['url'] = Avatar::url($filename);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError(_('The image could not be resized and cropped. '.$e), 422);
|
||||
}
|
||||
|
||||
// save in profile_prefs
|
||||
try {
|
||||
Profile_prefs::setData($this->scoped, 'qvitter', 'cover_photo', $result['url']);
|
||||
} catch (ServerException $e) {
|
||||
$this->clientError(_('The image could not be resized and cropped. '.$e), 422);
|
||||
}
|
||||
|
||||
// return json
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($result);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Undocumented Twitter API used by Twidere (not implemented yet) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiActivityAboutMeUnreadAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$json_obects = array();
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($json_obects);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -46,65 +46,83 @@ class ApiExternalUserShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$profileurl = urldecode($this->arg('profileurl'));
|
||||
$this->format = 'json';
|
||||
|
||||
// if this is an instance/user/1234 type url, try to find real profile url
|
||||
if(strstr($profileurl, '/user/')) {
|
||||
|
||||
$redrected_profileurl = $this->getRedirectUrl($profileurl);
|
||||
if (!empty($redrected_profileurl)) {
|
||||
$profileurl = $redrected_profileurl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// get local profile
|
||||
$local_profile = Profile::getKV('profileurl',$profileurl);
|
||||
$profileurl = urldecode($this->arg('profileurl'));
|
||||
$nickname = urldecode($this->arg('nickname'));
|
||||
|
||||
$this->profile = new stdClass();
|
||||
$this->profile->external = null;
|
||||
$this->profile->local = null;
|
||||
|
||||
// we can get urls of two types of urls (1) ://instance/nickname
|
||||
// (2) ://instance/user/1234
|
||||
//
|
||||
// in case (1) we have the problem that the html can be outdated,
|
||||
// i.e. the user can have changed her nickname. we also have no idea
|
||||
// if it is a multi or single user instance, which forces us to
|
||||
// guess the api root url.
|
||||
//
|
||||
// in case (2) we have another problem: we can't use that url to find
|
||||
// the local profile for the external user, we need url:s of type (2)
|
||||
// for that. so we have to try getting the nickname from the external
|
||||
// instance first
|
||||
|
||||
|
||||
// case (2)
|
||||
if(strstr($profileurl, '/user/')) {
|
||||
|
||||
$external_user_id = substr($profileurl,strpos($profileurl,'/user/')+6);
|
||||
$external_instance_url = substr($profileurl,0,strpos($profileurl,'/user/')+1);
|
||||
|
||||
if(!is_numeric($external_user_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$external_profile = $this->getProfileFromExternalInstance($external_instance_url,$external_user_id);
|
||||
|
||||
if(!isset($external_profile->statusnet_profile_url)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->profile->external = $external_profile;
|
||||
$local_profile = Profile::getKV('profileurl',$external_profile->statusnet_profile_url);
|
||||
|
||||
if(!$local_profile instanceof Profile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if($local_profile) {
|
||||
$this->profile->local = $this->twitterUserArray($local_profile);
|
||||
|
||||
$username = $this->profile->local['screen_name'];
|
||||
|
||||
// if profile url is not ending with nickname, this is probably a single user instance
|
||||
if(!substr($profileurl, -strlen($username))===$username) {
|
||||
$instanceurl = $profileurl;
|
||||
}
|
||||
|
||||
// multi user instance
|
||||
else {
|
||||
$instanceurl = substr($profileurl, 0, strrpos($profileurl, '/'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// we don't know this user
|
||||
else {
|
||||
|
||||
// if profile url ends with '/' this is probably an unknown single user instance
|
||||
if(substr($profileurl, -1)==='/') {
|
||||
$instanceurl = $profileurl;
|
||||
$username = 1;
|
||||
}
|
||||
|
||||
// case (1)
|
||||
$local_profile = Profile::getKV('profileurl',$profileurl);
|
||||
|
||||
if($local_profile instanceof Profile) {
|
||||
|
||||
// if profile url is not ending with nickname, this is probably a single user instance
|
||||
if(!substr($local_profile->profileurl, -strlen($local_profile->nickname))===$local_profile->nickname) {
|
||||
$external_instance_url = $local_profile->profileurl;
|
||||
}
|
||||
// multi user instance
|
||||
else {
|
||||
$username = substr($profileurl, strrpos($profileurl, '/')+1);
|
||||
$instanceurl = substr($profileurl, 0, strrpos($profileurl, '/'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// get profile from external instance
|
||||
$apicall = $instanceurl.'/api/users/show.json?id='.$username;
|
||||
$client = new HTTPClient();
|
||||
$response = $client->get($apicall);
|
||||
// json_decode returns null if it fails to decode
|
||||
$this->profile->external = $response->isOk() ? json_decode($response->getBody()) : null;
|
||||
$external_instance_url = substr($local_profile->profileurl, 0, strrpos($local_profile->profileurl, '/'));
|
||||
}
|
||||
|
||||
$external_profile = $this->getProfileFromExternalInstance($external_instance_url,$local_profile->nickname);
|
||||
|
||||
if(!isset($external_profile->statusnet_profile_url)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->profile->external = $external_profile;
|
||||
$this->profile->local = $this->twitterUserArray($local_profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,9 +138,13 @@ class ApiExternalUserShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->profile);
|
||||
$this->endDocument('json');
|
||||
if(is_null($this->profile->local) && is_null($this->profile->external)) {
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
} else {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->profile);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,19 +160,21 @@ class ApiExternalUserShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get redirect(s) for an url
|
||||
* Get profile from external instance
|
||||
*
|
||||
* @return mixed Location URL if redirect, null if no Location header (through HTTP_Request2_Response getHeader())
|
||||
* @return null or profile object
|
||||
*/
|
||||
function getRedirectUrl ($url) {
|
||||
function getProfileFromExternalInstance($instance_url,$user_id_or_nickname)
|
||||
{
|
||||
$apicall = $instance_url.'/api/users/show.json?id='.$user_id_or_nickname;
|
||||
$client = new HTTPClient();
|
||||
$response = $client->head($url);
|
||||
return $response->getHeader('Location'); // null if it isn't set
|
||||
$response = $client->get($apicall);
|
||||
// json_decode returns null if it fails to decode
|
||||
return $response->isOk() ? json_decode($response->getBody()) : null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -46,14 +46,15 @@ class ApiFavsAndRepeatsAction extends ApiPrivateAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->notice_id = $this->trimmed('notice_id');
|
||||
$this->format = 'json';
|
||||
|
||||
$this->notice_id = $this->trimmed('notice_id');
|
||||
|
||||
$this->original = Notice::getKV('id', $this->notice_id);
|
||||
|
||||
if (empty($this->original)) {
|
||||
// TRANS: Client error displayed trying to display redents of a non-exiting notice.
|
||||
$this->clientError(_('No such notice.'),
|
||||
400, $this->format);
|
||||
$this->clientError(_('No such notice.'), 400);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -80,20 +81,30 @@ class ApiFavsAndRepeatsAction extends ApiPrivateAuthAction
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
|
||||
|
||||
|
||||
// since this api method is in practice only used when expanding a
|
||||
// notice, we can assume the user has seen the notice in question,
|
||||
// an no longer need a notification about it. mark reply/mention-
|
||||
// notifications tied to this notice and the current profile as read
|
||||
if($this->auth_user) {
|
||||
QvitterPlugin::markNotificationAsSeen($this->notice_id,$this->auth_user->id,'mention');
|
||||
QvitterPlugin::markNotificationAsSeen($this->notice_id,$this->auth_user->id,'reply');
|
||||
}
|
||||
|
||||
|
||||
// favs
|
||||
$fave = new Fave();
|
||||
$fave->selectAdd();
|
||||
$fave->selectAdd();
|
||||
$fave->selectAdd('user_id');
|
||||
$fave->selectAdd('modified');
|
||||
$fave->selectAdd('modified');
|
||||
$fave->notice_id = $this->original->id;
|
||||
$fave->orderBy('modified');
|
||||
if (!is_null($this->cnt)) {
|
||||
$fave->limit(0, $this->cnt);
|
||||
}
|
||||
$fav_ids = $fave->fetchAll('user_id', 'modified');
|
||||
|
||||
|
||||
// get nickname and profile image
|
||||
$fav_ids_with_profile_data = array();
|
||||
$i=0;
|
||||
@@ -101,29 +112,30 @@ class ApiFavsAndRepeatsAction extends ApiPrivateAuthAction
|
||||
$profile = Profile::getKV('id', $id);
|
||||
$fav_ids_with_profile_data[$i]['user_id'] = $id;
|
||||
$fav_ids_with_profile_data[$i]['nickname'] = $profile->nickname;
|
||||
$fav_ids_with_profile_data[$i]['fullname'] = $profile->fullname;
|
||||
$fav_ids_with_profile_data[$i]['fullname'] = $profile->fullname;
|
||||
$fav_ids_with_profile_data[$i]['profileurl'] = $profile->profileurl;
|
||||
$fav_ids_with_profile_data[$i]['time'] = strtotime($time);
|
||||
$fav_ids_with_profile_data[$i]['time'] = strtotime($time);
|
||||
$profile = new Profile();
|
||||
$profile->id = $id;
|
||||
$avatarurl = $profile->avatarUrl(48);
|
||||
$fav_ids_with_profile_data[$i]['avatarurl'] = $avatarurl;
|
||||
$fav_ids_with_profile_data[$i]['avatarurl'] = $avatarurl;
|
||||
$i++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// repeats
|
||||
$notice = new Notice();
|
||||
$notice->selectAdd(); // clears it
|
||||
$notice->selectAdd('profile_id');
|
||||
$notice->selectAdd('created');
|
||||
$notice->selectAdd('profile_id');
|
||||
$notice->selectAdd('created');
|
||||
$notice->repeat_of = $this->original->id;
|
||||
$notice->verb = ActivityVerb::SHARE;
|
||||
$notice->orderBy('created, id'); // NB: asc!
|
||||
if (!is_null($this->cnt)) {
|
||||
$notice->limit(0, $this->cnt);
|
||||
}
|
||||
$repeat_ids = $notice->fetchAll('profile_id','created');
|
||||
|
||||
|
||||
// get nickname and profile image
|
||||
$repeat_ids_with_profile_data = array();
|
||||
$i=0;
|
||||
@@ -131,18 +143,18 @@ class ApiFavsAndRepeatsAction extends ApiPrivateAuthAction
|
||||
$profile = Profile::getKV('id', $id);
|
||||
$repeat_ids_with_profile_data[$i]['user_id'] = $id;
|
||||
$repeat_ids_with_profile_data[$i]['nickname'] = $profile->nickname;
|
||||
$repeat_ids_with_profile_data[$i]['fullname'] = $profile->fullname;
|
||||
$repeat_ids_with_profile_data[$i]['profileurl'] = $profile->profileurl;
|
||||
$repeat_ids_with_profile_data[$i]['time'] = strtotime($time);
|
||||
$repeat_ids_with_profile_data[$i]['fullname'] = $profile->fullname;
|
||||
$repeat_ids_with_profile_data[$i]['profileurl'] = $profile->profileurl;
|
||||
$repeat_ids_with_profile_data[$i]['time'] = strtotime($time);
|
||||
$profile = new Profile();
|
||||
$profile->id = $id;
|
||||
$avatarurl = $profile->avatarUrl(48);
|
||||
$repeat_ids_with_profile_data[$i]['avatarurl'] = $avatarurl;
|
||||
$repeat_ids_with_profile_data[$i]['avatarurl'] = $avatarurl;
|
||||
$i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$favs_and_repeats = array('favs'=>$fav_ids_with_profile_data,'repeats'=>$repeat_ids_with_profile_data);
|
||||
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($favs_and_repeats);
|
||||
$this->endDocument('json');
|
||||
@@ -162,6 +174,6 @@ class ApiFavsAndRepeatsAction extends ApiPrivateAuthAction
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Everybody I'm following and all groups I'm member of ·
|
||||
· (to use for auto-suggestions) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· (to use for auto-suggestions) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
@@ -19,9 +19,9 @@
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
@@ -36,7 +36,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
||||
|
||||
var $profiles = null;
|
||||
var $users_stripped = null;
|
||||
var $groups_stripped = null;
|
||||
var $blocks = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
@@ -60,6 +62,8 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->count = 5000; // max 5000, completely arbitrary...
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
@@ -71,20 +75,41 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
$this->groups = $this->getGroups();
|
||||
$this->blocks = QvitterBlocked::getBlockedIDs($this->target->id,0,10000);
|
||||
|
||||
|
||||
// only keep id, name, nickname and avatar URL
|
||||
|
||||
// profiles: only keep id, name, nickname and avatar URL
|
||||
foreach($this->profiles as $p) {
|
||||
try {
|
||||
$avatar = Avatar::byProfile($p, AVATAR_STREAM_SIZE);
|
||||
$avatar = $avatar->url;
|
||||
$avatar = Avatar::urlByProfile($p, AVATAR_STREAM_SIZE);
|
||||
} catch (Exception $e) {
|
||||
$avatar = false;
|
||||
}
|
||||
}
|
||||
$this_user = array($p->fullname,$p->nickname,$avatar);
|
||||
if(!$p->isLocal()) {
|
||||
$this_user[3] = $p->getUrl();
|
||||
}
|
||||
else {
|
||||
$this_user[3] = false;
|
||||
}
|
||||
$this->users_stripped[$p->id] = $this_user;
|
||||
}
|
||||
|
||||
// groups: only keep id, name, nickname, avatar and local aliases
|
||||
foreach($this->groups as $user_group) {
|
||||
$p = $user_group->getProfile();
|
||||
$avatar = $user_group->stream_logo;
|
||||
$this_group = array($p->fullname,$p->nickname,$avatar);
|
||||
if(!$user_group->isLocal()) {
|
||||
$this_group[3] = $p->getUrl();
|
||||
}
|
||||
else {
|
||||
$this_group[3] = false;
|
||||
}
|
||||
$this->groups_stripped[$user_group->id] = $this_group;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -98,13 +123,13 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->users_stripped);
|
||||
$this->showJsonObjects(array('users'=>$this->users_stripped,'groups'=>$this->groups_stripped,'blocks'=>$this->blocks));
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get profiles
|
||||
*
|
||||
@@ -117,16 +142,10 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
||||
|
||||
$subs = null;
|
||||
|
||||
if (isset($this->tag)) {
|
||||
$subs = $this->target->getTaggedSubscriptions(
|
||||
$this->tag, $offset, $limit
|
||||
);
|
||||
} else {
|
||||
$subs = $this->target->getSubscribed(
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
$subs = $this->target->getSubscribed(
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
|
||||
$profiles = array();
|
||||
|
||||
@@ -137,4 +156,29 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups
|
||||
*
|
||||
* @return array groups
|
||||
*/
|
||||
function getGroups()
|
||||
{
|
||||
$groups = array();
|
||||
|
||||
$group = $this->target->getGroups(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
if(!empty($group)) {
|
||||
while ($group->fetch()) {
|
||||
$groups[] = clone($group);
|
||||
}
|
||||
}
|
||||
return $groups;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· API for getting all blocked profiles for a profile ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
class ApiQvitterBlocksAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->count = (int)$this->arg('count', 100);
|
||||
|
||||
$arg_user = $this->getTargetUser($this->arg('id'));
|
||||
|
||||
$this->target = ($this->auth_user) ? $this->auth_user->getProfile() : null;
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting a list of followers for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
} else if($this->auth_user->id != $arg_user->id) {
|
||||
$this->clientError(_('You are only allowed to view your own blocks.'), 403);
|
||||
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the profiles
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$this->initDocument('json');
|
||||
print json_encode($this->showProfiles());
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user's blocked profiles
|
||||
*
|
||||
* @return array Profiles
|
||||
*/
|
||||
protected function getProfiles()
|
||||
{
|
||||
$offset = ($this->page - 1) * $this->count;
|
||||
$limit = $this->count + 1;
|
||||
|
||||
$blocks = null;
|
||||
|
||||
$blocks = QvitterBlocked::getBlocked($this->target->id, $offset, $limit);
|
||||
|
||||
if($blocks) {
|
||||
$profiles = array();
|
||||
|
||||
while ($blocks->fetch()) {
|
||||
$this_profile_block = clone($blocks);
|
||||
$profiles[] = $this->getTargetProfile($this_profile_block->blocked);
|
||||
}
|
||||
return $profiles;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest profile in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->modified);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this action
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last profiles in the subscriptions list
|
||||
* There's also an indicator to show whether this action is being called
|
||||
* as /api/statuses/(friends|followers) or /api/(friends|followers)/ids
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
'Profiles',
|
||||
strtotime($this->profiles[0]->modified),
|
||||
strtotime($this->profiles[$last]->modified))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the profiles as Twitter-style useres and statuses
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showProfiles()
|
||||
{
|
||||
$user_arrays = array();
|
||||
foreach ($this->profiles as $profile) {
|
||||
$user_arrays[] = $this->twitterUserArray($profile, false );
|
||||
}
|
||||
return $user_arrays;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check email
|
||||
*
|
||||
* Returns 1 if email is already in use on this instance, 0 if not. Error if site is private.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterCheckEmailAction extends ApiAction
|
||||
{
|
||||
var $email = null;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->email = $this->trimmed('email');
|
||||
|
||||
if(!Validate::email($this->email, common_config('email', 'check_domain'))) {
|
||||
$this->clientError('Not a valid email address.', 400);
|
||||
}
|
||||
|
||||
if (common_config('site', 'private')) {
|
||||
$this->clientError(_('This site is private.'), 403);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if($this->emailExists($this->email)) {
|
||||
$email_exists = 1;
|
||||
} else {
|
||||
$email_exists = 0;
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($email_exists);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the given email address already exist?
|
||||
*
|
||||
* Checks a canonical email address against the database.
|
||||
*
|
||||
* @param string $email email address to check
|
||||
*
|
||||
* @return boolean true if the address already exists
|
||||
*/
|
||||
function emailExists($email)
|
||||
{
|
||||
$user = User::getKV('email', $email);
|
||||
return is_object($user);
|
||||
}
|
||||
}
|
||||
@@ -57,29 +57,37 @@ class ApiQvitterCheckLoginAction extends ApiAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle($args);
|
||||
parent::handle();
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
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
|
||||
);
|
||||
$this->clientError(_('This method requires a POST.'), 400);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$user = common_check_user($this->arg('username'),
|
||||
$this->arg('password'));
|
||||
|
||||
if($user) {
|
||||
$user = true;
|
||||
$this->arg('password'));
|
||||
|
||||
if(!$user instanceof User) {
|
||||
$this->clientError(_('Incorrect credentials.'), 401);
|
||||
}
|
||||
|
||||
// silenced?
|
||||
if($user->isSilenced()) {
|
||||
$this->clientError(_('User '.json_encode($user->isSilenced()).' is silenced.'), 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$profile = $user->getProfile();
|
||||
} catch (UserNoProfileException $e) {
|
||||
$this->clientError(_('User got no profile.'), 400);
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($user);
|
||||
$this->showJsonObjects($this->twitterUserArray($profile));
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Say hello to the API ·
|
||||
· (you will also get headers with e.g. unread notification count....) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterHelloAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects('hello');
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List a list's members
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* List 20 newest admins of the group specified by name or ID.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiQvitterListMembersAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $list = null;
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->list = $this->getTargetList($this->arg('nickname'), $this->arg('id'));
|
||||
if (!$this->list instanceof Profile_list) {
|
||||
// TRANS: Client error displayed trying to show list membership on a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the admin of the group
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showJsonUsers($this->profiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the admins of a group
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
function getProfiles()
|
||||
{
|
||||
$profiles = array();
|
||||
|
||||
$profile = $this->list->getTagged(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$profiles[] = clone($profile);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this list of profiles last modified?
|
||||
*
|
||||
* @return string datestamp of the lastest profile in the group
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language
|
||||
* the group id, and timestamps of the first and last
|
||||
* user who has joined the group
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List a list's members
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* List 20 newest admins of the group specified by name or ID.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiQvitterListSubscribersAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $list = null;
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->list = $this->getTargetList($this->arg('nickname'), $this->arg('id'));
|
||||
if (!$this->list instanceof Profile_list) {
|
||||
// TRANS: Client error displayed trying to show list membership on a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the admin of the group
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showJsonUsers($this->profiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the admins of a group
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
function getProfiles()
|
||||
{
|
||||
$profiles = array();
|
||||
|
||||
$profile = $this->list->getSubscribers(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$profiles[] = clone($profile);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this list of profiles last modified?
|
||||
*
|
||||
* @return string datestamp of the lastest profile in the group
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language
|
||||
* the group id, and timestamps of the first and last
|
||||
* user who has joined the group
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Say hello to the API ·
|
||||
· (you will also get headers with e.g. unread notification count....) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterMarkAllNotificationsAsSeenAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$n = new QvitterNotification();
|
||||
$n->selectAdd();
|
||||
$n->selectAdd('id');
|
||||
$n->whereAdd(sprintf('qvitternotification.to_profile_id = "%s"', $n->escape($this->auth_user->id)));
|
||||
$ids = $n->fetchAll('id');
|
||||
$notifications = QvitterNotification::pivotGet('id', $ids);
|
||||
$notifications = new ArrayWrapper($notifications);
|
||||
$notifications = $notifications->fetchAll();
|
||||
foreach($notifications as $notification) {
|
||||
if($notification->is_seen == 0) {
|
||||
$orig = clone($notification);
|
||||
$notification->is_seen = 1;
|
||||
$notification->update($orig);
|
||||
}
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects(true);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· API for getting all muted profiles for a profile ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
|
||||
class ApiQvitterMutesAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->count = (int)$this->arg('count', 100);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the profiles
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$this->target = Profile::current();
|
||||
|
||||
if(!$this->target instanceof Profile) {
|
||||
$this->clientError(_('You have to be logged in to view your mutes.'), 403);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
$this->initDocument('json');
|
||||
print json_encode($this->showProfiles());
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user's muted profiles
|
||||
*
|
||||
* @return array Profiles
|
||||
*/
|
||||
protected function getProfiles()
|
||||
{
|
||||
$offset = ($this->page - 1) * $this->count;
|
||||
$limit = $this->count;
|
||||
|
||||
$mutes = QvitterMuted::getMutedProfiles($this->target->id, $offset, $limit);
|
||||
|
||||
if($mutes) {
|
||||
return $mutes;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest profile in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->modified);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this action
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last profiles in the subscriptions list
|
||||
* There's also an indicator to show whether this action is being called
|
||||
* as /api/statuses/(friends|followers) or /api/(friends|followers)/ids
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
'Profiles',
|
||||
strtotime($this->profiles[0]->modified),
|
||||
strtotime($this->profiles[$last]->modified))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the profiles as Twitter-style useres and statuses
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showProfiles()
|
||||
{
|
||||
$user_arrays = array();
|
||||
if($this->profiles !== false) {
|
||||
foreach ($this->profiles as $profile) {
|
||||
$user_arrays[] = $this->twitterUserArray($profile, false );
|
||||
}
|
||||
}
|
||||
return $user_arrays;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -14,7 +14,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -30,7 +30,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
@@ -55,6 +55,8 @@ class ApiQvitterNotificationsAction extends ApiPrivateAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->notifications = $this->getNotifications();
|
||||
|
||||
return true;
|
||||
@@ -82,7 +84,7 @@ class ApiQvitterNotificationsAction extends ApiPrivateAuthAction
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$notice = null;
|
||||
$notice = null;
|
||||
|
||||
$notifications_populated = array();
|
||||
|
||||
@@ -93,7 +95,15 @@ class ApiQvitterNotificationsAction extends ApiPrivateAuthAction
|
||||
if($notification->notice_id === null) {
|
||||
continue;
|
||||
} else {
|
||||
$notice = self::twitterSimpleStatusArray(Notice::getKV($notification->notice_id));
|
||||
$notice_object = Notice::getKV($notification->notice_id);
|
||||
if($notice_object instanceof Notice) {
|
||||
$notice = self::twitterSimpleStatusArray($notice_object);
|
||||
} else {
|
||||
// if the referenced notice is missing, delete this corrupt notification!
|
||||
$notification->delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +119,9 @@ class ApiQvitterNotificationsAction extends ApiPrivateAuthAction
|
||||
'created_at'=>self::dateTwitter($notification->created),
|
||||
'is_seen'=>$notification->is_seen
|
||||
);
|
||||
} else {
|
||||
// if the referenced from_profile is missing, delete this corrupt notification!
|
||||
$notification->delete();
|
||||
}
|
||||
|
||||
// mark as seen
|
||||
@@ -134,17 +147,17 @@ class ApiQvitterNotificationsAction extends ApiPrivateAuthAction
|
||||
$notices = array();
|
||||
|
||||
$profile = ($this->auth_user) ? $this->auth_user->getProfile() : null;
|
||||
|
||||
|
||||
if(!$profile instanceof Profile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$stream = new NotificationStream($profile);
|
||||
|
||||
$notifications = $stream->getNotifications(($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
$this->max_id);
|
||||
|
||||
$notifications = $notifications->fetchAll();
|
||||
|
||||
@@ -205,5 +218,5 @@ class ApiQvitterNotificationsAction extends ApiPrivateAuthAction
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Qvitter's Oembed response for notices ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterOembedNoticeAction extends ApiAction
|
||||
{
|
||||
var $format = null;
|
||||
var $url = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = $this->arg('format');
|
||||
$this->url = $this->arg('url');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$noticeurl = common_path('notice/', StatusNet::isHTTPS());
|
||||
$instanceurl = common_path('', StatusNet::isHTTPS());
|
||||
|
||||
// remove protocol for the comparison below
|
||||
$noticeurl_wo_protocol = preg_replace('(^https?://)', '', $noticeurl);
|
||||
$instanceurl_wo_protocol = preg_replace('(^https?://)', '', $instanceurl);
|
||||
$url_wo_protocol = preg_replace('(^https?://)', '', $this->url);
|
||||
|
||||
// find local notice
|
||||
if(strpos($url_wo_protocol, $noticeurl_wo_protocol) === 0) {
|
||||
$possible_notice_id = str_replace($noticeurl_wo_protocol,'',$url_wo_protocol);
|
||||
if(ctype_digit($possible_notice_id)) {
|
||||
$notice = Notice::getKV('id',$possible_notice_id);;
|
||||
} else {
|
||||
$this->clientError("Notice not found.", 404);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$notice instanceof Notice){
|
||||
// TRANS: Client error displayed in oEmbed action when notice not found.
|
||||
// TRANS: %s is a notice.
|
||||
$this->clientError(sprintf(_("Notice %s not found."),$this->id), 404);
|
||||
}
|
||||
$profile = $notice->getProfile();
|
||||
if (!$profile instanceof Profile) {
|
||||
// TRANS: Server error displayed in oEmbed action when notice has not profile.
|
||||
$this->serverError(_('Notice has no profile.'), 500);
|
||||
}
|
||||
$authorname = $profile->getFancyName();
|
||||
|
||||
$oembed=array();
|
||||
$oembed['version']='1.0';
|
||||
$oembed['provider_name']=common_config('site', 'name');
|
||||
$oembed['provider_url']=common_root_url();
|
||||
$oembed['type']='link';
|
||||
|
||||
// TRANS: oEmbed title. %1$s is the author name, %2$s is the creation date.
|
||||
$oembed['title'] = ApiAction::dateTwitter($notice->created).' (Qvitter)';
|
||||
$oembed['author_name']=$authorname;
|
||||
$oembed['author_url']=$profile->profileurl;
|
||||
$oembed['url']=$notice->getUrl();
|
||||
$oembed['html']=$notice->getRendered();
|
||||
|
||||
// maybe add thumbnail
|
||||
$attachments = $notice->attachments();
|
||||
if (!empty($attachments)) {
|
||||
foreach ($attachments as $attachment) {
|
||||
if(is_object($attachment)) {
|
||||
try {
|
||||
$thumb = $attachment->getThumbnail();
|
||||
} catch (ServerException $e) {
|
||||
//
|
||||
}
|
||||
if(!empty($thumb) && method_exists('File_thumbnail','url')) {
|
||||
try {
|
||||
$thumb_url = File_thumbnail::url($thumb->filename);
|
||||
$oembed['thumbnail_url'] = $thumb_url;
|
||||
break; // only first one
|
||||
} catch (ClientException $e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
print json_encode($oembed);
|
||||
$this->endDocument('json');
|
||||
} elseif ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->elementStart('oembed');
|
||||
foreach(array(
|
||||
'version', 'type', 'provider_name',
|
||||
'provider_url', 'title', 'author_name',
|
||||
'author_url', 'url', 'html'
|
||||
) as $key) {
|
||||
if (isset($oembed[$key]) && $oembed[$key]!='') {
|
||||
$this->element($key, null, $oembed[$key]);
|
||||
}
|
||||
}
|
||||
$this->elementEnd('oembed');
|
||||
$this->endDocument('xml');
|
||||
} else {
|
||||
$this->serverError(sprintf(_('Format %s not supported.'), $this->format), 501);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
<?php
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Update the cover photo ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Sandbox a user ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -17,9 +17,10 @@
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
@@ -34,16 +35,15 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiUpdateCoverPhotoAction extends ApiAuthAction
|
||||
class ApiQvitterSandboxCreateAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
@@ -57,54 +57,47 @@ class ApiUpdateCoverPhotoAction extends ApiAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->format = 'json';
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
$this->cropW = $this->trimmed('cropW');
|
||||
$this->cropH = $this->trimmed('cropH');
|
||||
$this->cropX = $this->trimmed('cropX');
|
||||
$this->cropY = $this->trimmed('cropY');
|
||||
$this->img = $this->trimmed('img');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$base64img = $this->img;
|
||||
if(stristr($base64img, 'image/jpeg')) {
|
||||
$base64img_mime = 'image/jpeg';
|
||||
}
|
||||
elseif(stristr($base64img, 'image/png')) {
|
||||
// should convert to jpg here!!
|
||||
$base64img_mime = 'image/png';
|
||||
}
|
||||
$base64img = str_replace('data:image/jpeg;base64,', '', $base64img);
|
||||
$base64img = str_replace('data:image/png;base64,', '', $base64img);
|
||||
$base64img = str_replace(' ', '+', $base64img);
|
||||
$base64img_hash = md5($base64img);
|
||||
$base64img = base64_decode($base64img);
|
||||
$base64img_basename = basename('cover');
|
||||
$base64img_filename = File::filename($profile, $base64img_basename, $base64img_mime);
|
||||
$base64img_path = File::path($base64img_filename);
|
||||
$base64img_success = file_put_contents($base64img_path, $base64img);
|
||||
$base64img_mimetype = MediaFile::getUploadedMimeType($base64img_path, $base64img_filename);
|
||||
$mediafile = new MediaFile($profile, $base64img_filename, $base64img_mimetype);
|
||||
$imagefile = new ImageFile($mediafile->fileRecord->id, File::path($mediafile->filename));
|
||||
$imagefile->resizeTo(File::path($mediafile->filename), array('width'=>$this->cropW, 'height'=>$this->cropH, 'x'=>$this->cropX, 'y'=>$this->cropY, 'w'=>$this->cropW, 'h'=>$this->cropH));
|
||||
$result['url'] = File::url($mediafile->filename);
|
||||
|
||||
Profile_prefs::setData($profile, 'qvitter', 'cover_photo', $result['url']);
|
||||
|
||||
if (!$this->other instanceof Profile) {
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if ($this->scoped->id == $this->other->id) {
|
||||
$this->clientError(_("You cannot sandbox yourself!"), 403);
|
||||
}
|
||||
|
||||
if (!$this->scoped->hasRight(Right::SANDBOXUSER)) {
|
||||
$this->clientError(_('You cannot sandbox users on this site.'), 403);
|
||||
}
|
||||
|
||||
// only sandbox of the user isn't sandboxed
|
||||
if (!$this->other->isSandboxed()) {
|
||||
try {
|
||||
$this->other->sandbox();
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($result);
|
||||
$this->endDocument('json');
|
||||
$this->showJsonObjects($this->twitterUserArray($this->other));
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Unsandbox a user ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterSandboxDestroyAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!$this->other instanceof Profile) {
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if ($this->scoped->id == $this->other->id) {
|
||||
$this->clientError(_("You cannot unsandbox yourself!"), 403);
|
||||
}
|
||||
|
||||
if (!$this->scoped->hasRight(Right::SANDBOXUSER)) {
|
||||
$this->clientError(_('You cannot unsandbox users on this site.'), 403);
|
||||
}
|
||||
|
||||
// only unsandbox if the user is sandboxed
|
||||
if ($this->other->isSandboxed()) {
|
||||
try {
|
||||
$this->other->unsandbox();
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->twitterUserArray($this->other));
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List all sandboxed users on the instance
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiQvitterSandboxedAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// XXX: RSS and Atom
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUsers($this->profiles);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonUsers($this->profiles);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the sandboxed profiles
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
function getProfiles()
|
||||
{
|
||||
$profiles = array();
|
||||
|
||||
$profile = $this->getSandboxed(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count);
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$profiles[] = clone($profile);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the sandboxed profiles from DB
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
|
||||
function getSandboxed($offset=null, $limit=null) // offset is null because DataObject wants it, 0 would mean no results
|
||||
{
|
||||
|
||||
$profiles = new Profile();
|
||||
$profiles->joinAdd(array('id', 'profile_role:profile_id'));
|
||||
$profiles->whereAdd(sprintf('profile_role.role = \'%s\'', Profile_role::SANDBOXED));
|
||||
$profiles->orderBy('profile_role.created DESC');
|
||||
$profiles->limit($offset, $limit);
|
||||
$profiles->find();
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this list of profiles last modified?
|
||||
*
|
||||
* @return string datestamp of the lastest profile
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list
|
||||
*
|
||||
* Returns an Etag based on the action name, language
|
||||
* and timestamps of the first and last profile
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Set any topic in Profile_prefs ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterSetProfilePrefAction extends ApiAuthAction
|
||||
{
|
||||
var $prefNamespace = null;
|
||||
var $prefTopic = null;
|
||||
var $prefData = null;
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->prefNamespace = $this->trimmed('namespace');
|
||||
$this->prefTopic = $this->trimmed('topic');
|
||||
$this->prefData = $this->trimmed('data');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// save the new bookmarks
|
||||
$saved = Profile_prefs::setData($this->scoped, $this->prefNamespace, $this->prefTopic, $this->prefData);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($saved);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Silence a user ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterSilenceCreateAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!$this->other instanceof Profile) {
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if ($this->scoped->id == $this->other->id) {
|
||||
$this->clientError(_("You cannot silence yourself!"), 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->other->silenceAs($this->scoped);
|
||||
} catch (AlreadyFulfilledException $e) {
|
||||
// don't throw client error here, just return the user array like
|
||||
// if we successfully silenced the user. the client is only interested
|
||||
// in making sure the user is silenced.
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->twitterUserArray($this->other));
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List all silenced users on the instance
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiQvitterSilencedAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// XXX: RSS and Atom
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUsers($this->profiles);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonUsers($this->profiles);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the silenced profiles
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
function getProfiles()
|
||||
{
|
||||
$profiles = array();
|
||||
|
||||
$profile = $this->getSilenced(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count);
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$profiles[] = clone($profile);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the silenced profiles from DB
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
|
||||
function getSilenced($offset=null, $limit=null) // offset is null because DataObject wants it, 0 would mean no results
|
||||
{
|
||||
$profiles = new Profile();
|
||||
$profiles->joinAdd(array('id', 'profile_role:profile_id'));
|
||||
$profiles->whereAdd(sprintf('profile_role.role = \'%s\'', Profile_role::SILENCED));
|
||||
$profiles->orderBy('profile_role.created DESC');
|
||||
$profiles->limit($offset, $limit);
|
||||
$profiles->find();
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this list of profiles last modified?
|
||||
*
|
||||
* @return string datestamp of the lastest profile
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list
|
||||
*
|
||||
* Returns an Etag based on the action name, language
|
||||
* and timestamps of the first and last profile
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Unsilence a user ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterSilenceDestroyAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!$this->other instanceof Profile) {
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if ($this->scoped->id == $this->other->id) {
|
||||
$this->clientError(_("You cannot unsilence yourself!"), 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->other->unsilenceAs($this->scoped);
|
||||
} catch (AlreadyFulfilledException $e) {
|
||||
// don't throw client error here, just return the user array like
|
||||
// if we successfully unsilenced the user. the client is only interested
|
||||
// in making sure the user is unsilenced.
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->twitterUserArray($this->other));
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Post a notice (update your status) through the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page statusesupdate statuses/update
|
||||
|
||||
@section Description
|
||||
Updates the authenticating user's status. Requires the status parameter specified below.
|
||||
Request must be a POST.
|
||||
|
||||
@par URL pattern
|
||||
/api/statuses/update.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json
|
||||
|
||||
@par HTTP Method(s)
|
||||
POST
|
||||
|
||||
@par Requires Authentication
|
||||
Yes
|
||||
|
||||
@param status (Required) The URL-encoded text of the status update.
|
||||
@param source (Optional) The source application name, if using HTTP authentication or an anonymous OAuth consumer.
|
||||
@param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to.
|
||||
@param lat (Optional) The latitude the status refers to.
|
||||
@param long (Optional) The longitude the status refers to.
|
||||
@param media (Optional) a media upload, such as an image or movie file.
|
||||
|
||||
@sa @ref authentication
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li If the @e source parameter is not supplied the source of the status will default to 'api'. When authenticated via a registered OAuth application, the application's registered name and URL will always override the source parameter.
|
||||
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
|
||||
to encode the latitude and longitude (see example response below <georss:point>).
|
||||
@li Data uploaded via the @e media parameter should be multipart/form-data encoded.
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl -u username:password http://example.com/api/statuses/update.xml -d status='Howdy!' -d lat='30.468' -d long='-94.743'
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<status>
|
||||
<text>Howdy!</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Tue Mar 30 23:28:05 +0000 2010</created_at>
|
||||
<in_reply_to_status_id/>
|
||||
<source>api</source>
|
||||
<id>26668724</id>
|
||||
<in_reply_to_user_id/>
|
||||
<in_reply_to_screen_name/>
|
||||
<geo xmlns:georss="http://www.georss.org/georss">
|
||||
<georss:point>30.468 -94.743</georss:point>
|
||||
</geo>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>25803</id>
|
||||
<name>Jed Sanders</name>
|
||||
<screen_name>jedsanders</screen_name>
|
||||
<location>Hoop and Holler, Texas</location>
|
||||
<description>I like to think of myself as America's Favorite.</description>
|
||||
<profile_image_url>http://avatar.example.com/25803-48-20080924200604.png</profile_image_url>
|
||||
<url>http://jedsanders.net</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>5</followers_count>
|
||||
<profile_background_color/>
|
||||
<profile_text_color/>
|
||||
<profile_link_color/>
|
||||
<profile_sidebar_fill_color/>
|
||||
<profile_sidebar_border_color/>
|
||||
<friends_count>2</friends_count>
|
||||
<created_at>Wed Sep 24 20:04:00 +0000 2008</created_at>
|
||||
<favourites_count>0</favourites_count>
|
||||
<utc_offset>0</utc_offset>
|
||||
<time_zone>UTC</time_zone>
|
||||
<profile_background_image_url/>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>70</statuses_count>
|
||||
<following>true</following>
|
||||
<notifications>true</notifications>
|
||||
</user>
|
||||
</status>
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the authenticating user's status (posts a notice).
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiQvitterStatusesUpdateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $status = null;
|
||||
var $in_reply_to_status_id = null;
|
||||
var $lat = null;
|
||||
var $lon = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->status = $this->trimmed('status');
|
||||
$this->post_to_groups = $this->trimmed('post_to_groups');
|
||||
$this->lat = $this->trimmed('lat');
|
||||
$this->lon = $this->trimmed('long');
|
||||
|
||||
$this->in_reply_to_status_id
|
||||
= intval($this->trimmed('in_reply_to_status_id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
|
||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']), 400);
|
||||
}
|
||||
|
||||
if (empty($this->status)) {
|
||||
// TRANS: Client error displayed when the parameter "status" is missing.
|
||||
$this->clientError(_('Client must provide a \'status\' parameter with a value.'), 400);
|
||||
}
|
||||
|
||||
if (is_null($this->scoped)) {
|
||||
// TRANS: Client error displayed when updating a status for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
/* Do not call shortenlinks until the whole notice has been build */
|
||||
|
||||
// Check for commands
|
||||
|
||||
$inter = new CommandInterpreter();
|
||||
$cmd = $inter->handle_command($this->auth_user, $this->status);
|
||||
|
||||
if ($cmd) {
|
||||
if ($this->supported($cmd)) {
|
||||
$cmd->execute(new Channel());
|
||||
}
|
||||
|
||||
// Cmd not supported? Twitter just returns your latest status.
|
||||
// And, it returns your last status whether the cmd was successful
|
||||
// or not!
|
||||
|
||||
$this->notice = $this->auth_user->getCurrentNotice();
|
||||
} else {
|
||||
$reply_to = null;
|
||||
|
||||
if (!empty($this->in_reply_to_status_id)) {
|
||||
// Check whether notice actually exists
|
||||
|
||||
$reply = Notice::getKV($this->in_reply_to_status_id);
|
||||
|
||||
if ($reply) {
|
||||
$reply_to = $this->in_reply_to_status_id;
|
||||
} else {
|
||||
// TRANS: Client error displayed when replying to a non-existing notice.
|
||||
$this->clientError(_('Parent notice not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
$upload = null;
|
||||
|
||||
try {
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
// There was no uploaded media for us today.
|
||||
}
|
||||
|
||||
if (isset($upload)) {
|
||||
$this->status .= ' ' . $upload->shortUrl();
|
||||
|
||||
/* Do not call shortenlinks until the whole notice has been build */
|
||||
}
|
||||
|
||||
// in Qvitter we shorten _before_ posting, so disble shortening here
|
||||
$status_shortened = $this->status;
|
||||
|
||||
if (Notice::contentTooLong($status_shortened)) {
|
||||
if ($upload instanceof MediaFile) {
|
||||
$upload->delete();
|
||||
}
|
||||
// TRANS: Client error displayed exceeding the maximum notice length.
|
||||
// TRANS: %d is the maximum lenth for a notice.
|
||||
$msg = _m('Maximum notice size is %d character, including attachment URL.',
|
||||
'Maximum notice size is %d characters, including attachment URL.',
|
||||
Notice::maxContent());
|
||||
/* Use HTTP 413 error code (Request Entity Too Large)
|
||||
* instead of basic 400 for better understanding
|
||||
*/
|
||||
$this->clientError(sprintf($msg, Notice::maxContent()), 413);
|
||||
}
|
||||
|
||||
|
||||
$content = html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$options = array('reply_to' => $reply_to);
|
||||
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// -------- Qvitter's post-to-the-right-group stuff! -----------
|
||||
// -------------------------------------------------------------
|
||||
|
||||
// guess the groups by the content first, if we don't have group id:s as meta data
|
||||
$profile = Profile::getKV('id', $this->scoped->id);
|
||||
$guessed_groups = User_group::groupsFromText($content, $profile);
|
||||
|
||||
// if the user has specified any group id:s, correct the guesswork
|
||||
if(strlen($this->post_to_groups)>0) {
|
||||
// get the groups that the user wants to post to
|
||||
$group_ids = explode(':',$this->post_to_groups);
|
||||
$correct_groups = Array();
|
||||
foreach($group_ids as $group_id) {
|
||||
$correct_groups[] = User_group::getKV('id',$group_id);
|
||||
}
|
||||
|
||||
// correct the guesses
|
||||
$corrected_group_ids = Array();
|
||||
foreach($guessed_groups as $guessed_group) {
|
||||
$id_to_keep = $guessed_group->id;
|
||||
foreach($correct_groups as $k=>$correct_group) {
|
||||
if($correct_group->nickname == $guessed_group->nickname) {
|
||||
$id_to_keep = $correct_group->id;
|
||||
unset($correct_groups[$k]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$corrected_group_ids[$id_to_keep] = true;
|
||||
}
|
||||
|
||||
// but we still want to post to all of the groups that the user specified by id
|
||||
// even if we couldn't use it to correct a bad guess
|
||||
foreach($correct_groups as $correct_group) {
|
||||
$corrected_group_ids[$correct_group->id] = true;
|
||||
}
|
||||
|
||||
$options['groups'] = array_keys($corrected_group_ids);
|
||||
}
|
||||
|
||||
// if the user didn't send any group id:s, go with the guesses
|
||||
else {
|
||||
$guessed_ids = array();
|
||||
foreach ($guessed_groups as $guessed_group) {
|
||||
$guessed_ids[$guessed_group->id] = true;
|
||||
}
|
||||
$options['groups'] = array_keys($guessed_ids);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// ------ End of Qvitter's post-to-the-right-group stuff! ------
|
||||
// -------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
if ($this->scoped->shareLocation()) {
|
||||
|
||||
$locOptions = Notice::locationOptions($this->lat,
|
||||
$this->lon,
|
||||
null,
|
||||
null,
|
||||
$this->scoped);
|
||||
|
||||
$options = array_merge($options, $locOptions);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->notice = Notice::saveNew(
|
||||
$this->scoped->id,
|
||||
$content,
|
||||
$this->source,
|
||||
$options
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
if (isset($upload)) {
|
||||
$upload->attachToNotice($this->notice);
|
||||
}
|
||||
}
|
||||
|
||||
$this->showNotice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the resulting notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->show_single_json_status($this->notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this command supported when doing an update from the API?
|
||||
*
|
||||
* @param string $cmd the command to check for
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function supported($cmd)
|
||||
{
|
||||
static $cmdlist = array('SubCommand', 'UnsubCommand',
|
||||
'OnCommand', 'OffCommand', 'JoinCommand', 'LeaveCommand');
|
||||
|
||||
$supported = null;
|
||||
|
||||
if (Event::handle('CommandSupportedAPI', array($cmd, &$supported))) {
|
||||
$supported = $supported || in_array(get_class($cmd), $cmdlist);
|
||||
}
|
||||
|
||||
return $supported;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) in the list
|
||||
*/
|
||||
|
||||
class ApiQvitterTimelineListAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
var $list = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->list = $this->getTargetList($this->arg('nickname'), $this->arg('id'));
|
||||
if (!($this->list instanceof Profile_list)) {
|
||||
// TRANS: Client error displayed when requesting a non existing list
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showJsonTimeline($this->notices);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = new PeopletagNoticeStream($this->list);
|
||||
|
||||
$notice = $stream->getNotices(($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
$notices = $notice->fetchAll();
|
||||
|
||||
NoticeList::prefill($notices);
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -15,7 +15,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -31,7 +31,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
@@ -53,6 +53,8 @@ class ApiQvitterUpdateBackgroundColorAction extends ApiAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->backgroundcolor = $this->trimmed('backgroundcolor');
|
||||
return true;
|
||||
}
|
||||
@@ -70,16 +72,16 @@ class ApiQvitterUpdateBackgroundColorAction extends ApiAuthAction
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
|
||||
$validhex = preg_match('/^[a-f0-9]{6}$/i',$this->backgroundcolor);
|
||||
if ($validhex === false || $validhex == 0) {
|
||||
$this->clientError(_('Not a valid hex color.'), 400);
|
||||
}
|
||||
|
||||
|
||||
Profile_prefs::setData($this->scoped, 'theme', 'backgroundcolor', $this->backgroundcolor);
|
||||
|
||||
|
||||
// unset background-image
|
||||
Profile_prefs::setData($this->scoped, 'qvitter', 'background_image', '');
|
||||
Profile_prefs::setData($this->scoped, 'qvitter', 'background_image', '');
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->scoped, true);
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Update the user's bookmarks ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterUpdateBookmarksAction extends ApiAuthAction
|
||||
{
|
||||
var $bookmarks = null;
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->bookmarks = $this->trimmed('bookmarks');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// save the new bookmarks
|
||||
$saved = Profile_prefs::setData($this->scoped, 'qvitter', 'bookmarks', $this->bookmarks);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($saved);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -15,7 +15,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -31,10 +31,10 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiQvitterUpdateLinkColorAction extends ApiAuthAction
|
||||
@@ -54,6 +54,8 @@ class ApiQvitterUpdateLinkColorAction extends ApiAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->linkcolor = $this->trimmed('linkcolor');
|
||||
|
||||
return true;
|
||||
@@ -72,12 +74,12 @@ class ApiQvitterUpdateLinkColorAction extends ApiAuthAction
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
|
||||
$validhex = preg_match('/^[a-f0-9]{6}$/i',$this->linkcolor);
|
||||
if ($validhex === false || $validhex == 0) {
|
||||
$this->clientError(_('Not a valid hex color.'), 400);
|
||||
}
|
||||
|
||||
|
||||
// save the new color
|
||||
Profile_prefs::setData($this->scoped, 'theme', 'linkcolor', $this->linkcolor);
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Saved searches (not implemented yet) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiSavedSearchesListAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$json_obects = array();
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($json_obects);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the friends timeline, witch replies to non-friends hidden
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page friendstimeline statuses/friends_timeline
|
||||
|
||||
@section Description
|
||||
Returns the 20 most recent statuses posted by the authenticating
|
||||
user and that user's friends. This is the equivalent of "You and
|
||||
friends" page in the web interface.
|
||||
|
||||
@par URL patterns
|
||||
@li /api/statuses/friends_timeline.:format
|
||||
@li /api/statuses/friends_timeline/:id.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json, rss, atom
|
||||
|
||||
@par ID (:id)
|
||||
username, user id
|
||||
|
||||
@par HTTP Method(s)
|
||||
GET
|
||||
|
||||
@par Requires Authentication
|
||||
Sometimes (see: @ref authentication)
|
||||
|
||||
@param user_id (Optional) Specifies a user by ID
|
||||
@param screen_name (Optional) Specifies a user by screename (nickname)
|
||||
@param since_id (Optional) Returns only statuses with an ID greater
|
||||
than (that is, more recent than) the specified ID.
|
||||
@param max_id (Optional) Returns only statuses with an ID less than
|
||||
(that is, older than) or equal to the specified ID.
|
||||
@param count (Optional) Specifies the number of statuses to retrieve.
|
||||
@param page (Optional) Specifies the page of results to retrieve.
|
||||
|
||||
@sa @ref authentication
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
|
||||
to encode the latitude and longitude (see example response below <georss:point>).
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0"?>
|
||||
<statuses type="array">
|
||||
<status>
|
||||
<text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
|
||||
<in_reply_to_status_id/>
|
||||
<source><a href="http://code.google.com/p/microblog-purple/">mbpidgin</a></source>
|
||||
<id>26674201</id>
|
||||
<in_reply_to_user_id/>
|
||||
<in_reply_to_screen_name/>
|
||||
<geo/>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>246</id>
|
||||
<name>Mark</name>
|
||||
<screen_name>lambic</screen_name>
|
||||
<location>Montreal, Canada</location>
|
||||
<description>Geek</description>
|
||||
<profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
|
||||
<url>http://lambic.co.uk</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>73</followers_count>
|
||||
<profile_background_color>#F0F2F5</profile_background_color>
|
||||
<profile_text_color/>
|
||||
<profile_link_color>#002E6E</profile_link_color>
|
||||
<profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
|
||||
<profile_sidebar_border_color/>
|
||||
<friends_count>58</friends_count>
|
||||
<created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
|
||||
<favourites_count>2</favourites_count>
|
||||
<utc_offset>-14400</utc_offset>
|
||||
<time_zone>US/Eastern</time_zone>
|
||||
<profile_background_image_url/>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>933</statuses_count>
|
||||
<following>false</following>
|
||||
<notifications>false</notifications>
|
||||
</user>
|
||||
</status>
|
||||
</statuses>
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the target user.
|
||||
* This is the equivalent of 'You and friends' page accessed via Web.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineFriendsHiddenRepliesAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Title of API timeline for a user and friends.
|
||||
// TRANS: %s is a username.
|
||||
$title = sprintf(_("%s and friends"), $this->target->nickname);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:FriendsTimelineHiddenReplies:" . $this->target->id;
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
|
||||
_('Updates from %1$s and friends on %2$s! (with replies to non-friends hidden)'),
|
||||
$this->target->nickname,
|
||||
$sitename
|
||||
);
|
||||
|
||||
$logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$link = common_local_url('all',
|
||||
array('nickname' => $this->target->nickname));
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($logo);
|
||||
$atom->setUpdated('now');
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user, $title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = new InboxNoticeStreamHiddenReplies($this->target, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stream of notices for a profile's "all" feed, with hidden replies to non-friends
|
||||
*
|
||||
* @category General
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @copyright 2014 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class InboxNoticeStreamHiddenReplies extends ScopingNoticeStream
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Profile $target Profile to get a stream for
|
||||
* @param Profile $scoped Currently scoped profile (if null, it is fetched)
|
||||
*/
|
||||
function __construct(Profile $target, Profile $scoped=null)
|
||||
{
|
||||
if ($scoped === null) {
|
||||
$scoped = Profile::current();
|
||||
}
|
||||
// FIXME: we don't use CachingNoticeStream - but maybe we should?
|
||||
parent::__construct(new CachingNoticeStream(new RawInboxNoticeStreamHiddenReplies($target), 'profileallhiddenreplies'), $scoped);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw stream of notices for the target's inbox, with hidden replies to non-friends
|
||||
*
|
||||
* @category General
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class RawInboxNoticeStreamHiddenReplies extends NoticeStream
|
||||
{
|
||||
protected $target = null;
|
||||
protected $inbox = null;
|
||||
|
||||
protected $selectVerbs = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Profile $target Profile to get a stream for
|
||||
*/
|
||||
function __construct(Profile $target)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->target = $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IDs in a range
|
||||
*
|
||||
* @param int $offset Offset from start
|
||||
* @param int $limit Limit of number to get
|
||||
* @param int $since_id Since this notice
|
||||
* @param int $max_id Before this notice
|
||||
*
|
||||
* @return Array IDs found
|
||||
*/
|
||||
function getNoticeIds($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$notice = new Notice();
|
||||
$notice->selectAdd();
|
||||
$notice->selectAdd('id');
|
||||
$notice->whereAdd(sprintf('notice.created > "%s"', $notice->escape($this->target->created)));
|
||||
// Reply:: is a table of mentions
|
||||
// Subscription:: is a table of subscriptions (every user is subscribed to themselves)
|
||||
$notice->whereAdd(
|
||||
|
||||
// notices from profiles we subscribe to
|
||||
sprintf('( notice.profile_id IN (SELECT subscribed FROM subscription WHERE subscriber=%1$d) ' .
|
||||
|
||||
// and in groups we're members of
|
||||
'OR notice.id IN (SELECT notice_id FROM group_inbox WHERE group_id IN (SELECT group_id FROM group_member WHERE profile_id=%1$d))' .
|
||||
|
||||
// and from attention table (i, hannes, don't know whats in that though...)
|
||||
'OR notice.id IN (SELECT notice_id FROM attention WHERE profile_id=%1$d) ) ' .
|
||||
|
||||
// all of the notices matching the above must also be either
|
||||
// 1) a non-reply
|
||||
'AND (notice.reply_to IS NULL ' .
|
||||
|
||||
// 2) OR a reply to myself
|
||||
'OR notice.profile_id=%1$d ' .
|
||||
|
||||
// 3) OR a reply to someone i'm subscibing to
|
||||
'OR notice.reply_to IN (SELECT id FROM notice as noticereplies WHERE noticereplies.profile_id IN (SELECT subscribed FROM subscription WHERE subscriber=%1$d))) '.
|
||||
|
||||
// lastly: include all notices mentioning me
|
||||
'OR (notice.id IN (SELECT notice_id FROM reply WHERE profile_id=%1$d) ' .
|
||||
|
||||
// but not if they are from someone i don't subscribe to
|
||||
'AND notice.profile_id IN (SELECT subscribed FROM subscription WHERE subscriber=%1$d))',
|
||||
|
||||
$this->target->id)
|
||||
);
|
||||
if (!empty($since_id)) {
|
||||
$notice->whereAdd(sprintf('notice.id > %d', $since_id));
|
||||
}
|
||||
if (!empty($max_id)) {
|
||||
$notice->whereAdd(sprintf('notice.id <= %d', $max_id));
|
||||
}
|
||||
|
||||
// We have changed how selectVerbs work in GNUsocial, so it's an associative array
|
||||
// where each verb is in the key and then the value (true/false) is how to filter.
|
||||
// $this->unselectVerbs is always unset in newer GNUsocials.
|
||||
if (!isset($this->unselectVerbs)) {
|
||||
self::filterVerbs($notice, $this->selectVerbs);
|
||||
} elseif (!empty($this->selectVerbs)) {
|
||||
// old behaviour was just if there were selectVerbs set
|
||||
$notice->whereAddIn('verb', $this->selectVerbs, $notice->columnType('verb'));
|
||||
}
|
||||
|
||||
$notice->limit($offset, $limit);
|
||||
// notice.id will give us even really old posts, which were
|
||||
// recently imported. For example if a remote instance had
|
||||
// problems and just managed to post here. Another solution
|
||||
// would be to have a 'notice.imported' field and order by it.
|
||||
$notice->orderBy('notice.id DESC');
|
||||
|
||||
if (!$notice->find()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$ids = $notice->fetchAll('id');
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -14,7 +14,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -30,7 +30,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
@@ -65,7 +65,7 @@ class ApiTimelinePublicAndExternalAction extends ApiPrivateAuthAction
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
function prepare($args)
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
@@ -79,13 +79,11 @@ class ApiTimelinePublicAndExternalAction extends ApiPrivateAuthAction
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle($args);
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -15,7 +15,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -31,10 +31,10 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiToggleQvitterAction extends ApiAuthAction
|
||||
@@ -57,9 +57,6 @@ class ApiToggleQvitterAction extends ApiAuthAction
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Try to save the user's colors in her design. Create a new design
|
||||
* if the user doesn't already have one.
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
@@ -70,29 +67,35 @@ class ApiToggleQvitterAction extends ApiAuthAction
|
||||
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
|
||||
|
||||
// what to toggle
|
||||
if(QvitterPlugin::settings('enabledbydefault')) {
|
||||
$state = Profile_prefs::getConfigData($profile, 'qvitter', 'disable_qvitter');
|
||||
if($state == 1) {
|
||||
Profile_prefs::setData($profile, 'qvitter', 'disable_qvitter', 0);
|
||||
}
|
||||
else {
|
||||
Profile_prefs::setData($profile, 'qvitter', 'disable_qvitter', 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$state = Profile_prefs::getConfigData($profile, 'qvitter', 'enable_qvitter');
|
||||
if($state == 1) {
|
||||
Profile_prefs::setData($profile, 'qvitter', 'enable_qvitter', 0);
|
||||
}
|
||||
else {
|
||||
Profile_prefs::setData($profile, 'qvitter', 'enable_qvitter', 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$result['success'] = true;
|
||||
|
||||
$toggle = 'disable_qvitter';
|
||||
} else {
|
||||
$toggle = 'enable_qvitter';
|
||||
}
|
||||
|
||||
// new value
|
||||
$state = Profile_prefs::getConfigData($profile, 'qvitter', $toggle);
|
||||
if($state == 1) {
|
||||
$new_state = 0;
|
||||
} else {
|
||||
$new_state = 1;
|
||||
}
|
||||
|
||||
try {
|
||||
$pref_saved = Profile_prefs::setData($profile, 'qvitter', $toggle, $new_state);
|
||||
$result['success'] = true;
|
||||
} catch (ServerException $e) {
|
||||
$result['success'] = false;
|
||||
$result['error'] = $e;
|
||||
}
|
||||
|
||||
if(!$pref_saved) {
|
||||
$result['success'] = false;
|
||||
$result['error'] = 'Probably couldn\'t get topic from pref table';
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($result);
|
||||
$this->endDocument('json');
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· API trends (not implemented yet) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiTrendsPlaceAction extends ApiAuthAction
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$json_obects = array();
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($json_obects);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
<?php
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Update the avatar
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
@@ -17,9 +17,9 @@
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
@@ -34,7 +34,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
@@ -57,14 +57,25 @@ class ApiUpdateAvatarAction extends ApiAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
$this->cropW = $this->trimmed('cropW');
|
||||
$this->cropH = $this->trimmed('cropH');
|
||||
$this->cropX = $this->trimmed('cropX');
|
||||
$this->cropY = $this->trimmed('cropY');
|
||||
$this->img = $this->trimmed('img');
|
||||
|
||||
$this->img = $this->trimmed('img');
|
||||
|
||||
$this->img = str_replace('data:image/jpeg;base64,', '', $this->img);
|
||||
$this->img = str_replace('data:image/png;base64,', '', $this->img);
|
||||
$this->img = str_replace(' ', '+', $this->img);
|
||||
$this->img = base64_decode($this->img);
|
||||
|
||||
if (empty($this->img)) {
|
||||
throw new ClientException(_('No uploaded image data.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,47 +88,34 @@ class ApiUpdateAvatarAction extends ApiAuthAction
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$base64img = $this->img;
|
||||
if(stristr($base64img, 'image/jpeg')) {
|
||||
$base64img_mime = 'image/jpeg';
|
||||
}
|
||||
elseif(stristr($base64img, 'image/png')) {
|
||||
// should convert to jpg here!!
|
||||
$base64img_mime = 'image/png';
|
||||
}
|
||||
$base64img = str_replace('data:image/jpeg;base64,', '', $base64img);
|
||||
$base64img = str_replace('data:image/png;base64,', '', $base64img);
|
||||
$base64img = str_replace(' ', '+', $base64img);
|
||||
$base64img_hash = md5($base64img);
|
||||
$base64img = base64_decode($base64img);
|
||||
$base64img_basename = basename('avatar');
|
||||
$base64img_filename = File::filename($profile, $base64img_basename, $base64img_mime);
|
||||
$base64img_path = File::path($base64img_filename);
|
||||
$base64img_success = file_put_contents($base64img_path, $base64img);
|
||||
$base64img_mimetype = MediaFile::getUploadedMimeType($base64img_path, $base64img_filename);
|
||||
$mediafile = new MediaFile($profile, $base64img_filename, $base64img_mimetype);
|
||||
$imagefile = new ImageFile($mediafile->fileRecord->id, File::path($mediafile->filename));
|
||||
$imagefile->resizeTo(File::path($mediafile->filename), array('width'=>$this->cropW, 'height'=>$this->cropH, 'x'=>$this->cropX, 'y'=>$this->cropY, 'w'=>$this->cropW, 'h'=>$this->cropH));
|
||||
|
||||
$type = $imagefile->preferredType();
|
||||
$imagefile = null;
|
||||
// write the image to a temporary file
|
||||
$fh = tmpfile();
|
||||
fwrite($fh, $this->img);
|
||||
unset($this->img); // no need to keep it in memory
|
||||
// seek back to position 0, so we don't read EOF directly
|
||||
fseek($fh, 0);
|
||||
// read the temporary file as an uploaded image, will store File object
|
||||
$mediafile = MediaFile::fromFilehandle($fh, $this->scoped);
|
||||
// Deletes the temporary file, if it was needed we stored it in fromFilehandle
|
||||
fclose($fh);
|
||||
|
||||
// Now try to get it as an ImageFile since it has some handy functions
|
||||
$imagefile = ImageFile::fromFileObject($mediafile->fileRecord);
|
||||
unset($mediafile); // This isn't needed in memory.
|
||||
|
||||
// Get an appropriate filename for the avatar
|
||||
$filename = Avatar::filename(
|
||||
$profile->id,
|
||||
image_type_to_extension($type),
|
||||
$this->scoped->getID(),
|
||||
image_type_to_extension($imagefile->preferredType()),
|
||||
null,
|
||||
common_timestamp()
|
||||
);
|
||||
$imagefile->resizeTo(Avatar::path($filename), array('width'=>$this->cropW, 'height'=>$this->cropH, 'x'=>$this->cropX, 'y'=>$this->cropY, 'w'=>$this->cropW, 'h'=>$this->cropH));
|
||||
|
||||
$filepath = Avatar::path($filename);
|
||||
$this->scoped->setOriginal($filename);
|
||||
|
||||
$imagefile->copyTo($filepath);
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$profile->setOriginal($filename);
|
||||
|
||||
$mediafile->delete();
|
||||
|
||||
$twitter_user = $this->twitterUserArray($profile, true);
|
||||
$twitter_user = $this->twitterUserArray($this->scoped, true);
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<?php
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Update the cover photo ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
@@ -17,9 +17,9 @@
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
@@ -34,7 +34,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
@@ -57,14 +57,25 @@ class ApiUpdateBackgroundImageAction extends ApiAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->format = 'json';
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
$this->cropW = $this->trimmed('cropW');
|
||||
$this->cropH = $this->trimmed('cropW'); // note W, we want a square
|
||||
$this->cropX = $this->trimmed('cropX');
|
||||
$this->cropY = $this->trimmed('cropY');
|
||||
$this->img = $this->trimmed('img');
|
||||
|
||||
$this->img = $this->trimmed('img');
|
||||
|
||||
$this->img = str_replace('data:image/jpeg;base64,', '', $this->img);
|
||||
$this->img = str_replace('data:image/png;base64,', '', $this->img);
|
||||
$this->img = str_replace(' ', '+', $this->img);
|
||||
$this->img = base64_decode($this->img);
|
||||
|
||||
if (empty($this->img)) {
|
||||
throw new ClientException(_('No uploaded image data.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,34 +88,38 @@ class ApiUpdateBackgroundImageAction extends ApiAuthAction
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$base64img = $this->img;
|
||||
if(stristr($base64img, 'image/jpeg')) {
|
||||
$base64img_mime = 'image/jpeg';
|
||||
}
|
||||
elseif(stristr($base64img, 'image/png')) {
|
||||
// should convert to jpg here!!
|
||||
$base64img_mime = 'image/png';
|
||||
}
|
||||
$base64img = str_replace('data:image/jpeg;base64,', '', $base64img);
|
||||
$base64img = str_replace('data:image/png;base64,', '', $base64img);
|
||||
$base64img = str_replace(' ', '+', $base64img);
|
||||
$base64img_hash = md5($base64img);
|
||||
$base64img = base64_decode($base64img);
|
||||
$base64img_basename = basename('bg');
|
||||
$base64img_filename = File::filename($profile, $base64img_basename, $base64img_mime);
|
||||
$base64img_path = File::path($base64img_filename);
|
||||
$base64img_success = file_put_contents($base64img_path, $base64img);
|
||||
$base64img_mimetype = MediaFile::getUploadedMimeType($base64img_path, $base64img_filename);
|
||||
$mediafile = new MediaFile($profile, $base64img_filename, $base64img_mimetype);
|
||||
$imagefile = new ImageFile($mediafile->fileRecord->id, File::path($mediafile->filename));
|
||||
$imagefile->resizeTo(File::path($mediafile->filename), array('width'=>1280, 'height'=>1280, 'x'=>$this->cropX, 'y'=>$this->cropY, 'w'=>$this->cropW, 'h'=>$this->cropH));
|
||||
$result['url'] = File::url($mediafile->filename);
|
||||
|
||||
Profile_prefs::setData($profile, 'qvitter', 'background_image', $result['url']);
|
||||
|
||||
$imagefile = null;
|
||||
|
||||
// put the image data in a temporary file
|
||||
$fh = tmpfile();
|
||||
fwrite($fh, $this->img);
|
||||
unset($this->img);
|
||||
fseek($fh, 0); // go to beginning just to be sure the content is read properly
|
||||
|
||||
// We get a MediaFile with a File object using the filehandle
|
||||
$mediafile = MediaFile::fromFilehandle($fh, $this->scoped);
|
||||
// and can dispose of the temporary filehandle since we're certain we have a File on disk now
|
||||
fclose($fh);
|
||||
|
||||
$imagefile = ImageFile::fromFileObject($mediafile->fileRecord);
|
||||
unset($mediafile); // No need to keep the MediaFile around anymore, everything we need is in ImageFile
|
||||
|
||||
// We're just using the Avatar function to build a filename here
|
||||
// but we don't save it _as_ an avatar below... but in the same dir!
|
||||
$filename = Avatar::filename(
|
||||
$this->scoped->getID(),
|
||||
image_type_to_extension($imagefile->preferredType()),
|
||||
null,
|
||||
'bg-'.common_timestamp()
|
||||
);
|
||||
|
||||
$imagefile->resizeTo(Avatar::path($filename), array('width'=>1280, 'height'=>1280, 'x'=>$this->cropX, 'y'=>$this->cropY, 'w'=>$this->cropW, 'h'=>$this->cropH));
|
||||
$result['url'] = Avatar::url($filename);
|
||||
|
||||
Profile_prefs::setData($this->scoped, 'qvitter', 'background_image', $result['url']);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($result);
|
||||
$this->endDocument('json');
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -15,7 +15,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -31,15 +31,13 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
|
||||
|
||||
|
||||
class QvitterAdminSettingsAction extends AdminPanelAction
|
||||
{
|
||||
@@ -85,15 +83,19 @@ class QvitterAdminSettingsAction extends AdminPanelAction
|
||||
function saveSettings()
|
||||
{
|
||||
$qvitterNotice = $this->trimmed('qvitter-notice');
|
||||
$qvitterNoticeLoggedOut = $this->trimmed('qvitter-notice-logged-out');
|
||||
|
||||
// assert(all values are valid);
|
||||
// This throws an exception on validation errors
|
||||
|
||||
$this->validate($qvitterNotice);
|
||||
$this->validate($qvitterNoticeLoggedOut);
|
||||
|
||||
$config = new Config();
|
||||
|
||||
$result = Config::save('site', 'qvitternotice', $qvitterNotice);
|
||||
$result = Config::save('site', 'qvitternoticeloggedout', $qvitterNoticeLoggedOut);
|
||||
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server error displayed when saving a sidebar notice was impossible.
|
||||
@@ -105,21 +107,13 @@ class QvitterAdminSettingsAction extends AdminPanelAction
|
||||
{
|
||||
// Validate notice text
|
||||
|
||||
if (mb_strlen($qvitterNotice) > 255) {
|
||||
//The column 'value' in table 'config' is TEXT
|
||||
if (mb_strlen($qvitterNotice) > 21844) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when a sidebar notice was longer than allowed.
|
||||
_('Maximum length for the sidebar notice is 255 characters.')
|
||||
_('Maximum length for the sidebar notice is 21844 characters.')
|
||||
);
|
||||
}
|
||||
|
||||
// scrub HTML input
|
||||
|
||||
$config = array(
|
||||
'safe' => 1,
|
||||
'deny_attribute' => 'on*'
|
||||
);
|
||||
|
||||
$qvitterNotice = htmLawed($qvitterNotice, $config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +169,22 @@ class QvitterNoticeAdminPanelForm extends AdminForm
|
||||
_('Qvitter sidebar notice text'),
|
||||
common_config('site', 'qvitternotice'),
|
||||
// TRANS: Tooltip for sidebar notice text field in admin panel.
|
||||
_('Qvitter\'s sidebar notice text (255 characters maximum; HTML allowed)')
|
||||
_('Qvitter\'s sidebar notice text (21,844 characters maximum; HTML allowed)')
|
||||
);
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->textarea(
|
||||
'qvitter-notice-logged-out',
|
||||
// TRANS: Label for sidebar notice text field in admin panel.
|
||||
_('Qvitter sidebar notice text (logged out)'),
|
||||
common_config('site', 'qvitternoticeloggedout'),
|
||||
// TRANS: Tooltip for sidebar notice text field in admin panel.
|
||||
_('Qvitter\'s sidebar notice text, when logged out (21,844 characters maximum; HTML allowed)')
|
||||
);
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -15,7 +15,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -31,7 +31,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
@@ -106,12 +106,23 @@ class QvitterLoginAction extends FormAction
|
||||
}
|
||||
|
||||
common_real_login(true);
|
||||
$this->updateScopedProfile();
|
||||
$this->updateScopedProfile();
|
||||
|
||||
if ($this->boolean('rememberme')) {
|
||||
common_rememberme($user);
|
||||
}
|
||||
|
||||
// make sure we have a unique app id for this Qvitter installation in config
|
||||
// to use for creating a csrf token
|
||||
if(common_config('qvitter', 'appid') == false) {
|
||||
Config::save('qvitter', 'appid', sha1(common_random_hexstr(16)));
|
||||
}
|
||||
|
||||
// set csrf-cookie
|
||||
$csrf_token = sha1(common_config('qvitter', 'appid').session_id());
|
||||
common_set_cookie('Qvitter-CSRF', $csrf_token, time() + 60*60*24*30); // 1 month
|
||||
|
||||
|
||||
$url = common_get_returnto();
|
||||
|
||||
if ($url) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -15,7 +15,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -31,7 +31,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
@@ -60,7 +60,7 @@ class QvitterSettingsAction extends SettingsAction
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Page instructions.
|
||||
return _m('Enable or disable Qvitter UI');
|
||||
return _m('Qvitter Settings');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,19 +74,32 @@ class QvitterSettingsAction extends SettingsAction
|
||||
|
||||
if(QvitterPlugin::settings('enabledbydefault')) {
|
||||
try {
|
||||
$prefs = Profile_prefs::getData($user->getProfile(), 'qvitter', 'disable_qvitter');
|
||||
$disable_enable_prefs = Profile_prefs::getData($user->getProfile(), 'qvitter', 'disable_qvitter');
|
||||
} catch (NoResultException $e) {
|
||||
$prefs = false;
|
||||
$disable_enable_prefs = false;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$prefs = Profile_prefs::getData($user->getProfile(), 'qvitter', 'enable_qvitter');
|
||||
$disable_enable_prefs = Profile_prefs::getData($user->getProfile(), 'qvitter', 'enable_qvitter');
|
||||
} catch (NoResultException $e) {
|
||||
$prefs = false;
|
||||
}
|
||||
}
|
||||
$disable_enable_prefs = false;
|
||||
}
|
||||
}
|
||||
|
||||
$form = new QvitterPrefsForm($this, $prefs);
|
||||
|
||||
try {
|
||||
$hide_replies_prefs = Profile_prefs::getData($user->getProfile(), 'qvitter', 'hide_replies');
|
||||
} catch (NoResultException $e) {
|
||||
$hide_replies_prefs = false;
|
||||
}
|
||||
|
||||
try {
|
||||
$disable_keyboard_shortcuts = Profile_prefs::getData($user->getProfile(), 'qvitter', 'disable_keyboard_shortcuts');
|
||||
} catch (NoResultException $e) {
|
||||
$disable_keyboard_shortcuts = false;
|
||||
}
|
||||
|
||||
$form = new QvitterPrefsForm($this, $disable_enable_prefs, $hide_replies_prefs, $disable_keyboard_shortcuts);
|
||||
|
||||
$form->show();
|
||||
}
|
||||
@@ -104,12 +117,16 @@ class QvitterSettingsAction extends SettingsAction
|
||||
$user = common_current_user();
|
||||
|
||||
if(QvitterPlugin::settings('enabledbydefault')) {
|
||||
Profile_prefs::setData($user->getProfile(), 'qvitter', 'disable_qvitter', $this->boolean('disable_qvitter'));
|
||||
Profile_prefs::setData($user->getProfile(), 'qvitter', 'disable_qvitter', $this->boolean('disable_qvitter'));
|
||||
}
|
||||
else {
|
||||
Profile_prefs::setData($user->getProfile(), 'qvitter', 'enable_qvitter', $this->boolean('enable_qvitter'));
|
||||
Profile_prefs::setData($user->getProfile(), 'qvitter', 'enable_qvitter', $this->boolean('enable_qvitter'));
|
||||
}
|
||||
|
||||
Profile_prefs::setData($user->getProfile(), 'qvitter', 'hide_replies', $this->boolean('hide_replies'));
|
||||
|
||||
Profile_prefs::setData($user->getProfile(), 'qvitter', 'disable_keyboard_shortcuts', $this->boolean('disable_keyboard_shortcuts'));
|
||||
|
||||
// TRANS: Confirmation shown when user profile settings are saved.
|
||||
$this->showForm(_('Settings saved.'), true);
|
||||
|
||||
@@ -119,12 +136,16 @@ class QvitterSettingsAction extends SettingsAction
|
||||
|
||||
class QvitterPrefsForm extends Form
|
||||
{
|
||||
var $prefs;
|
||||
var $disable_enable_prefs;
|
||||
var $hide_replies_prefs;
|
||||
var $disable_keyboard_shortcuts;
|
||||
|
||||
function __construct($out, $prefs)
|
||||
function __construct($out, $disable_enable_prefs, $hide_replies_prefs, $disable_keyboard_shortcuts)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->prefs = $prefs;
|
||||
$this->disable_enable_prefs = $disable_enable_prefs;
|
||||
$this->hide_replies_prefs = $hide_replies_prefs;
|
||||
$this->disable_keyboard_shortcuts = $disable_keyboard_shortcuts;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,21 +159,41 @@ class QvitterPrefsForm extends Form
|
||||
|
||||
function formData()
|
||||
{
|
||||
|
||||
|
||||
if(QvitterPlugin::settings('enabledbydefault')) {
|
||||
$enabledisable = 'disable_qvitter';
|
||||
$enabledisablelabel = _('Disable Qvitter');
|
||||
} else {
|
||||
$enabledisable = 'enable_qvitter';
|
||||
$enabledisablelabel = _('Enable Qvitter');
|
||||
}
|
||||
|
||||
$enabledisablelabel = _('Enable Qvitter');
|
||||
}
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox($enabledisable,
|
||||
$enabledisablelabel,
|
||||
(!empty($this->prefs)));
|
||||
(!empty($this->disable_enable_prefs)));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('hide_replies',
|
||||
_('Hide replies to people I\'m not following'),
|
||||
(!empty($this->hide_replies_prefs)));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('disable_keyboard_shortcuts',
|
||||
_('Disable keyboard shortcuts'),
|
||||
(!empty($this->disable_keyboard_shortcuts)));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
@@ -33,20 +33,59 @@ class NotificationStream
|
||||
*/
|
||||
function getNotificationIds($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
|
||||
$current_profile = Profile::current();
|
||||
|
||||
$notification = new QvitterNotification();
|
||||
$notification->selectAdd();
|
||||
$notification->selectAdd('id');
|
||||
$notification->whereAdd(sprintf('qvitternotification.to_profile_id = "%s"', $notification->escape($this->target->id)));
|
||||
$notification->whereAdd(sprintf('qvitternotification.created >= "%s"', $notification->escape($this->target->created)));
|
||||
|
||||
// if the user only want notifications from users they follow
|
||||
$only_show_notifications_from_users_i_follow = Profile_prefs::getConfigData($current_profile, 'qvitter', 'only_show_notifications_from_users_i_follow');
|
||||
if($only_show_notifications_from_users_i_follow == '1') {
|
||||
$notification->whereAdd(sprintf('qvitternotification.from_profile_id IN (SELECT subscribed FROM subscription WHERE subscriber = %u)', $current_profile->id));
|
||||
}
|
||||
|
||||
// the user might have opted out from notifications from profiles they have muted
|
||||
$hide_notifications_from_muted_users = Profile_prefs::getConfigData($current_profile, 'qvitter', 'hide_notifications_from_muted_users');
|
||||
if($hide_notifications_from_muted_users == '1') {
|
||||
$muted_ids = QvitterMuted::getMutedIDs($current_profile->id,0,10000); // get all (hopefully not more than 10 000...)
|
||||
if($muted_ids !== false && count($muted_ids) > 0) {
|
||||
$ids_imploded = implode(',',$muted_ids);
|
||||
$notification->whereAdd('qvitternotification.from_profile_id NOT IN ('.$ids_imploded.')');
|
||||
}
|
||||
}
|
||||
|
||||
// the user might have opted out from certain notification types
|
||||
$disable_notify_replies_and_mentions = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_replies_and_mentions');
|
||||
$disable_notify_favs = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_favs');
|
||||
$disable_notify_repeats = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_repeats');
|
||||
$disable_notify_follows = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_follows');
|
||||
if($disable_notify_replies_and_mentions == '1') {
|
||||
$notification->whereAdd('qvitternotification.ntype != "mention"');
|
||||
$notification->whereAdd('qvitternotification.ntype != "reply"');
|
||||
}
|
||||
if($disable_notify_favs == '1') {
|
||||
$notification->whereAdd('qvitternotification.ntype != "like"');
|
||||
}
|
||||
if($disable_notify_repeats == '1') {
|
||||
$notification->whereAdd('qvitternotification.ntype != "repeat"');
|
||||
}
|
||||
if($disable_notify_follows == '1') {
|
||||
$notification->whereAdd('qvitternotification.ntype != "follow"');
|
||||
}
|
||||
|
||||
$notification->limit($offset, $limit);
|
||||
$notification->orderBy('qvitternotification.created DESC');
|
||||
|
||||
if($since_id) {
|
||||
$notification->whereAdd(sprintf('qvitternotification.id > %d', $notification->escape($since_id)));
|
||||
$notification->whereAdd(sprintf('qvitternotification.id > %d', $notification->escape($since_id)));
|
||||
}
|
||||
|
||||
|
||||
if($max_id) {
|
||||
$notification->whereAdd(sprintf('qvitternotification.id <= %d', $notification->escape($max_id)));
|
||||
$notification->whereAdd(sprintf('qvitternotification.id <= %d', $notification->escape($max_id)));
|
||||
}
|
||||
|
||||
if (!$notification->find()) {
|
||||
@@ -84,7 +123,7 @@ class NotificationStream
|
||||
|
||||
return new ArrayWrapper($all);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· http://github.com/hannesmannerheim/qvitter ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
@@ -15,7 +15,7 @@
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter is free software: you can redistribute it and / or modify it ·
|
||||
· under the terms of the GNU Affero General Public License as published by ·
|
||||
@@ -31,7 +31,7 @@
|
||||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class PublicAndExternalNoticeStream extends ScopingNoticeStream
|
||||
{
|
||||
function __construct($profile=null)
|
||||
{
|
||||
|
||||
|
||||
parent::__construct(new CachingNoticeStream(new RawPublicAndExternalNoticeStream(),
|
||||
'publicAndExternal'),
|
||||
$profile);
|
||||
@@ -60,7 +60,7 @@ class RawPublicAndExternalNoticeStream extends NoticeStream
|
||||
$notice->selectAdd();
|
||||
$notice->selectAdd('id');
|
||||
|
||||
$notice->orderBy('created DESC, id DESC');
|
||||
$notice->orderBy('id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$notice->limit($offset, $limit);
|
||||
@@ -69,10 +69,27 @@ class RawPublicAndExternalNoticeStream extends NoticeStream
|
||||
|
||||
$notice->whereAdd('is_local !='. Notice::LOCAL_NONPUBLIC);
|
||||
$notice->whereAdd('is_local !='. Notice::GATEWAY);
|
||||
$notice->whereAdd('repeat_of IS NULL');
|
||||
$notice->whereAdd('repeat_of IS NULL');
|
||||
|
||||
Notice::addWhereSinceId($notice, $since_id);
|
||||
Notice::addWhereMaxId($notice, $max_id);
|
||||
// don't show sandboxed users in public timelines, unless you are a mod
|
||||
$hide_sandboxed = true;
|
||||
$cur_profile = Profile::current();
|
||||
if($cur_profile instanceof Profile) {
|
||||
if($cur_profile->hasRight(Right::REVIEWSPAM)) {
|
||||
$hide_sandboxed = false;
|
||||
}
|
||||
}
|
||||
if($hide_sandboxed) {
|
||||
$notice->whereAdd('profile_id NOT IN (SELECT profile_id FROM profile_role WHERE role =\''.Profile_role::SANDBOXED.'\')');
|
||||
}
|
||||
|
||||
if(!empty($max_id) && is_numeric($max_id)) {
|
||||
$notice->whereAdd('id < '.$max_id);
|
||||
}
|
||||
|
||||
if(!empty($since_id) && is_numeric($since_id)) {
|
||||
$notice->whereAdd('id > '.$since_id);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
@@ -84,7 +101,7 @@ class RawPublicAndExternalNoticeStream extends NoticeStream
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Extends GNU social's Profile_block class with useful functions ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class QvitterBlocked extends Profile_block
|
||||
{
|
||||
|
||||
const CACHE_WINDOW = 201;
|
||||
|
||||
public static function getBlocked($profile_id, $offset = 0, $limit = PROFILES_PER_PAGE)
|
||||
{
|
||||
$ids = self::getBlockedIDs($profile_id, $offset, $limit);
|
||||
try {
|
||||
$blocked = Profile_block::listFind('blocked', $ids);
|
||||
return $blocked;
|
||||
} catch(NoResultException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function getBlockedIDs($profile_id, $offset, $limit)
|
||||
{
|
||||
$cacheKey = 'qvitterblocked:'.$profile_id;
|
||||
|
||||
$queryoffset = $offset;
|
||||
$querylimit = $limit;
|
||||
|
||||
if ($offset + $limit <= self::CACHE_WINDOW) {
|
||||
// Oh, it seems it should be cached
|
||||
$ids = self::cacheGet($cacheKey);
|
||||
if (is_array($ids)) {
|
||||
return array_slice($ids, $offset, $limit);
|
||||
}
|
||||
// Being here indicates we didn't find anything cached
|
||||
// so we'll have to fill it up simultaneously
|
||||
$queryoffset = 0;
|
||||
$querylimit = self::CACHE_WINDOW;
|
||||
}
|
||||
|
||||
$blocks = new Profile_block();
|
||||
$blocks->blocker = $profile_id;
|
||||
$blocks->selectAdd('blocked');
|
||||
$blocks->whereAdd("blocked != {$profile_id}");
|
||||
$blocks->orderBy('modified DESC');
|
||||
$blocks->limit($queryoffset, $querylimit);
|
||||
|
||||
if (!$blocks->find()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$ids = $blocks->fetchAll('blocked');
|
||||
|
||||
// If we're simultaneously filling up cache, remember to slice
|
||||
if ($queryoffset === 0 && $querylimit === self::CACHE_WINDOW) {
|
||||
self::cacheSet($cacheKey, $ids);
|
||||
return array_slice($ids, $offset, $limit);
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush cached blocks when blocks are updated
|
||||
*
|
||||
* @param mixed $dataObject Original version of object
|
||||
*
|
||||
* @return boolean success flag.
|
||||
*/
|
||||
function update($dataObject=false)
|
||||
{
|
||||
self::blow('qvitterblocked:'.$this->blocker);
|
||||
self::blow('qvitterblocked:'.$this->blocked);
|
||||
|
||||
return parent::update($dataObject);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· Get muted profiles for a profile ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
· ·
|
||||
· https://git.gnu.io/h2p/Qvitter ·
|
||||
· ·
|
||||
· ·
|
||||
· <o) ·
|
||||
· /_//// ·
|
||||
· (____/ ·
|
||||
· (o< ·
|
||||
· o> \\\\_\ ·
|
||||
· \\) \____) ·
|
||||
· ·
|
||||
· ·
|
||||
· ·
|
||||
· Qvitter 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 three of the License or (at ·
|
||||
· your option) any later version. ·
|
||||
· ·
|
||||
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
|
||||
· WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class QvitterMuted
|
||||
{
|
||||
|
||||
public static function getMutedProfiles($profile_id, $offset = 0, $limit = PROFILES_PER_PAGE)
|
||||
{
|
||||
|
||||
$ids = self::getMutedIDs($profile_id, $offset, $limit);
|
||||
|
||||
if(count($ids) === 0) {
|
||||
return false;
|
||||
} else {
|
||||
$profiles = array();
|
||||
foreach($ids as $id) {
|
||||
try {
|
||||
$profiles[] = Profile::getByID($id);
|
||||
} catch (Exception $e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
if(count($profiles) === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return $profiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function getMutedIDs($profile_id, $offset, $limit)
|
||||
{
|
||||
|
||||
if(!is_numeric($profile_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mutes = new Profile_prefs();
|
||||
$mutes->selectAdd('topic');
|
||||
$mutes->whereAdd("profile_id = ".$profile_id);
|
||||
$mutes->whereAdd("namespace = 'qvitter'");
|
||||
$mutes->whereAdd("data = '1'");
|
||||
$mutes->whereAdd("topic LIKE 'mute:%'");
|
||||
$mutes->orderBy('modified DESC');
|
||||
$mutes->limit($offset, $limit);
|
||||
|
||||
if (!$mutes->find()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$topics = $mutes->fetchAll('topic');
|
||||
$ids = array();
|
||||
foreach($topics as $topic) {
|
||||
$topic_exploded = explode(':',$topic);
|
||||
if(is_numeric($topic_exploded[1])) {
|
||||
$ids[] = $topic_exploded[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -19,8 +19,8 @@ class QvitterNotification extends Managed_DataObject
|
||||
return array(
|
||||
'fields' => array(
|
||||
'id' => array('type' => 'serial', 'not null' => true),
|
||||
'to_profile_id' => array('type' => 'int', 'description' => 'the profile being notified'),
|
||||
'from_profile_id' => array('type' => 'int', 'description' => 'the profile that is notifying'),
|
||||
'to_profile_id' => array('type' => 'int', 'not null'=>true, 'description' => 'the profile being notified'),
|
||||
'from_profile_id' => array('type' => 'int', 'not null'=>true, 'description' => 'the profile that is notifying'),
|
||||
'ntype' => array('type' => 'varchar', 'length' => 7, 'description' => 'reply, like, mention or follow'),
|
||||
'notice_id' => array('type' => 'int', 'description' => 'id for the reply or mention or notice being faved'),
|
||||
'is_seen' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'if the notification has been seen'),
|
||||
@@ -30,7 +30,8 @@ class QvitterNotification extends Managed_DataObject
|
||||
'foreign keys' => array(
|
||||
'qvitternotification_to_profile_id_fkey' => array('profile', array('to_profile_id' => 'id')),
|
||||
'qvitternotification_from_profile_id_fkey' => array('profile', array('from_profile_id' => 'id')),
|
||||
'qvitternotification_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
|
||||
// removing this because there can be rows without related notice_id
|
||||
//'qvitternotification_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
|
||||
),
|
||||
'indexes' => array(
|
||||
'qvitternotification_created_idx' => array('created'),
|
||||
@@ -54,5 +55,52 @@ class QvitterNotification extends Managed_DataObject
|
||||
return $result;
|
||||
}
|
||||
|
||||
static public function beforeSchemaUpdate()
|
||||
{
|
||||
$table = strtolower(get_called_class());
|
||||
$schema = Schema::get();
|
||||
try {
|
||||
$schemadef = $schema->getTableDef($table);
|
||||
} catch (SchemaTableMissingException $e) {
|
||||
printfnq("\nTable '$table' not created yet, so nothing to do with it before Schema Update... DONE.");
|
||||
return;
|
||||
}
|
||||
|
||||
printfnq("\nEnsuring no NULL values for foreign keys in QvitterNotification...");
|
||||
// Because constraints to profile and notice table assume not null, we must
|
||||
// remove any values in these columns that are NULL (or 0), because they
|
||||
// are invalid anyway.
|
||||
$qn = new QvitterNotification();
|
||||
foreach (['to_profile_id', 'from_profile_id'] as $field) {
|
||||
$qn->whereAdd(sprintf('%s is NULL', $field), 'OR');
|
||||
$qn->whereAdd(sprintf('%s = 0', $field), 'OR');
|
||||
}
|
||||
if ($qn->find()) {
|
||||
printfnq(" removing {$qn->N} rows...");
|
||||
while ($qn->fetch()) {
|
||||
$qn->delete();
|
||||
}
|
||||
}
|
||||
printfnq("DONE.\n");
|
||||
|
||||
printfnq("Ensuring no dead profile or notice IDs are stored in QvitterNotification...");
|
||||
// We could probably build a single statement for this but I just want it done...
|
||||
// or maybe be smart and take it directly from our defined 'foreign keys'... but oh well!
|
||||
$constraints = ['to_profile_id' => 'profile:id',
|
||||
'from_profile_id' => 'profile:id'];
|
||||
foreach ($constraints as $field=>$foreign) {
|
||||
$qn = new QvitterNotification();
|
||||
$qn->selectAdd();
|
||||
$qn->selectAdd('qvitternotification.id'); // to avoid confusion with profile.id, also we only need the primary key
|
||||
$qn->joinAdd([$field, $foreign], 'LEFT');
|
||||
$qn->whereAdd(str_replace(':', '.', $foreign).' IS NULL');
|
||||
if ($qn->find()) {
|
||||
printfnq("\n{$field}: {$qn->N} rows...");
|
||||
while ($qn->fetch()) {
|
||||
$qn->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
printfnq("DONE.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<h3>Aktionen</h3>
|
||||
<p><span class="shortcut">n</span><span class="description">Neuer Queet</span></p>
|
||||
<p><span class="shortcut">f</span><span class="description">Als Favorit markieren</span></p>
|
||||
<p><span class="shortcut">r</span><span class="description">Antworten</span></p>
|
||||
<p><span class="shortcut">t</span><span class="description">Requeet</span></p>
|
||||
<p><span class="shortcut">Enter</span><span class="description">Queet erweitern</span></p>
|
||||
<p><span class="shortcut">Ctrl</span><span class="shortcut">Enter</span>oder <span class="shortcut">Cmd ⌘</span><span class="shortcut">Enter</span><span class="description">Queet posten</span></p>
|
||||
<p><span class="shortcut">Esc</span><span class="description">Alle erweiterten Queets zuklappen</span></p>
|
||||
|
||||
<h3>Navigation</h3>
|
||||
<p><span class="shortcut">?</span><span class="description">Dieses Menu</span></p>
|
||||
<p><span class="shortcut">j</span><span class="description">Nächster Queet</span></p>
|
||||
<p><span class="shortcut">k</span><span class="description">Vorheriger Queet</span></p>
|
||||
|
||||
<h3>Disable</h3>
|
||||
<p>Keyboard shortcuts can be turned off on <a href="{instance-url-with-protocol}settings/qvitter">the Qvitter settings page</a>.</p>
|
||||
@@ -1,31 +1,35 @@
|
||||
<p>{instance-name} ist kein Dienstleistungsanbieter und du kannst hier deshalb auch keine
|
||||
Dienstleistungen in Anspruch nehmen. {instance-name} ist nur ein kleiner Teil einer größeren
|
||||
dezentralen Community. Dies bedeutet ebenso, dass wir dem Inhalt dieser GNU social Instanz
|
||||
nicht neutral gegenüber stehen müssen. Wenn dir der Inhalt von {instance-name} und deren
|
||||
Bedingungen nicht zusagen, kannst du jederzeit zu einer anderen GNU social Instanz wechseln,
|
||||
oder eine eigene eröffnen. Du kannst dann trotzdem Nutzern von {instance-name} folgen.
|
||||
<p>{instance-name} ist kein Dienstleistungsanbieter und du kannst hier deshalb auch keine
|
||||
Dienstleistungen in Anspruch nehmen. {instance-name} ist nur ein kleiner Teil einer größeren
|
||||
dezentralen Community. Dies bedeutet ebenso, dass wir dem Inhalt dieser GNU social Instanz
|
||||
nicht neutral gegenüber stehen müssen. Wenn dir der Inhalt von {instance-name} und deren
|
||||
Bedingungen nicht zusagen, kannst du jederzeit zu einer anderen GNU social Instanz wechseln,
|
||||
oder eine eigene eröffnen. Du kannst dann trotzdem Nutzern von {instance-name} folgen.
|
||||
Diese und andere Nutzer können dir ebenfalls folgen, dich aber auch blockieren.</p>
|
||||
|
||||
<p>Im Vergleich zu kommerziellen Social Media Anbietern, bietet {instance-name} eine ganz andere
|
||||
Struktur. Es ist hier deshalb möglich, Nutzer vor Belästigungen und Unterdrückung zu schützen.
|
||||
<p>Im Vergleich zu kommerziellen Social Media Anbietern, bietet {instance-name} eine ganz andere
|
||||
Struktur. Es ist hier deshalb möglich, Nutzer vor Belästigungen und Unterdrückung zu schützen.
|
||||
Dieses geschieht aber ohne jegliche Zensur.</p>
|
||||
|
||||
<p>Auf {instance-name} werden Nutzer die andere Nutzer belästigen gelöscht. Wir gehen ebenfalls
|
||||
konsequent gegen Rassismus, Sexismus, Behindertenfeindlichkeit, Homo- und Transphobie vor.
|
||||
Derartige Äußerungen würden diese Webseite unsicher für andere Nutzer machen und deren
|
||||
<p>Auf {instance-name} werden Nutzer die andere Nutzer belästigen gelöscht. Wir gehen ebenfalls
|
||||
konsequent gegen Rassismus, Sexismus, Behindertenfeindlichkeit, Antisemitismus, Homo- und Transphobie vor.
|
||||
Derartige Äußerungen würden diese Webseite unsicher für andere Nutzer machen und deren
|
||||
Meinungsfreiheit einschränken.</p>
|
||||
|
||||
<p>Die öffentliche Zeitleiste ist ein sehr sensibler Ort. Deren Inhalt sehen neue Nutzer als
|
||||
erstes und auch alle registrierten Nutzer können hier die Mitteilungen die veröffentlich
|
||||
wurden sehen. Moderatoren können Benutzer jederzeit, vorübergehend oder dauerhaft, von der
|
||||
öffentlichen Zeitleiste ausschließen. Beachte bitte, dass die Anzeige deiner Mitteilungen
|
||||
<p>Die öffentliche Zeitleiste ist ein sehr sensibler Ort. Deren Inhalt sehen neue Nutzer als
|
||||
erstes und auch alle registrierten Nutzer können hier die Mitteilungen die veröffentlich
|
||||
wurden sehen. Moderatoren können Benutzer jederzeit, vorübergehend oder dauerhaft, von der
|
||||
öffentlichen Zeitleiste ausschließen. Beachte bitte, dass die Anzeige deiner Mitteilungen
|
||||
in der öffentlichen Zeitleiste ein Privileg und kein Anspruch ist.
|
||||
Auch wenn du von der öffentlichen Zeitliste ausgeschlossen wirst, kannst du trotzdem alle
|
||||
Auch wenn du von der öffentlichen Zeitliste ausgeschlossen wirst, kannst du trotzdem alle
|
||||
anderen Möglichkeiten weiterhin nutzen.</p>
|
||||
|
||||
<p>Werbung und kommerzielle Konten sind auf dieser Instanz nicht gestattet. Wir sind absolut
|
||||
unkommerziell und alle unsere Ausgaben werden durch Spenden von Einzelpersonen bezahlt.
|
||||
<a href="mailto:{instance-email}">Wir können dir helfen</a>, eine eigene GNU social Instanz
|
||||
<a href="mailto:{instance-email}">Wir können dir helfen</a>, eine eigene GNU social Instanz
|
||||
zu eröffnen, wenn du vorhast kommerzielle Angebote zu posten.</p>
|
||||
|
||||
<p>Der Inhalt dieser Seite ist lizensiert unter <a href="{instance-license-url}">{instance-license-title}</a>.</p>
|
||||
|
||||
<p>Each user is responsible for the content they submit. If you have any questions
|
||||
about something posted on this instance, contact the user in question first. As a last resort you
|
||||
can email the <a href="mailto:{instance-email}">admins</a>.</p>
|
||||
|
||||
@@ -76,7 +76,7 @@ oversized notices can be opened via web browser</em></p>
|
||||
— <em>Mustard 0.4.1</em> (Android 3.x - current) (a rather experimental new approach with newer look)<br>
|
||||
— <em>Mustard{MOD}</em> (Android 3.x - current)<br>
|
||||
<em>All Mustards support geolocation, upload and display of image attachments, display of oversized notices from instances with larger character limit (open as attachment)</em></p>
|
||||
<p>— <em>Twidere</em><br>
|
||||
<p>— <em>Twidere 2.9.12</em> (use only this version!)<br>
|
||||
— <em>Seesmic 1.7.6</em> (use only this version!) (closed source)<br>
|
||||
— <em>Zwitscher</em><br>
|
||||
— <em>Twydroid</em> (closed source)<br>
|
||||
@@ -241,14 +241,14 @@ That is, notices in the group are only visible to group members (they don't appe
|
||||
<p>and click "block" below their profile desription</p>
|
||||
<p>We don't recommend blocking people from remote instances as there are still issues with this feature.</p>
|
||||
|
||||
|
||||
<!-- 19 -->
|
||||
<h2 id="faq-19">How to follow someone on a remote instance <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>In New {instance-name}:</p>
|
||||
<p>When you click a remote nickname in New {instance-name} you are brought to a small profile window showing the full remote address, e.g., @blabla@status.vinilox.eu. Click the button "Follow". That should be all. </p>
|
||||
<p>When you click a remote nickname in New {instance-name} you are brought to a small profile window showing the full remote address, e.g., @blabla@status.vinilox.eu. Click the button "Follow". That should be all. </p>
|
||||
<p>In Classic {instance-name}:</p>
|
||||
<p>In Classic {instance-name} you're forwarded to the remote instance's user profile (which may differ in layout and theme from Classic {instance-name}). Look for the Subscribe-button (usually in the upper right). A subscription box opens and you are prompted to enter your own "webfinger address", i.e., {nickname}@{instance-url} Subscribe and you are redirected to your Classic {instance-name} page where you have to confirm the subscription.</p>
|
||||
|
||||
<p>In Classic {instance-name} you're forwarded to the remote instance's user profile (which may differ in layout and theme from Classic {instance-name}). Look for the Subscribe-button (usually in the upper right). A subscription box opens and you are prompted to enter your own "webfinger address", i.e., {nickname}@{instance-url} Subscribe and you are redirected to your Classic {instance-name} page where you have to confirm the subscription.</p>
|
||||
<p>Manually:</p>
|
||||
<p>If you know the nickname and the name of the remote instance, you can initiate remote following by visisting <a href=" {instance-url-with-protocol}/main/ostatussub">{instance-url-with-protocol}/main/ostatussub</a>.</p>
|
||||
|
||||
<!-- 20 -->
|
||||
<h2 id="faq-20">How to manage the visibility of your notices <a href="#faq-table-of-contents">Top</a></h2>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<h3>Actions</h3>
|
||||
<p><span class="shortcut">n</span><span class="description">New Queet</span></p>
|
||||
<p><span class="shortcut">f</span><span class="description">Mark as favorite</span></p>
|
||||
<p><span class="shortcut">r</span><span class="description">Reply</span></p>
|
||||
<p><span class="shortcut">t</span><span class="description">Requeet</span></p>
|
||||
<p><span class="shortcut">Enter</span><span class="description">Expand queet</span></p>
|
||||
<p><span class="shortcut">Ctrl</span><span class="shortcut">Enter</span>or <span class="shortcut">Cmd ⌘</span><span class="shortcut">Enter</span><span class="description">Post Queet</span></p>
|
||||
<p><span class="shortcut">Esc</span><span class="description">Collapse all expanded Queets</span></p>
|
||||
|
||||
<h3>Navigation</h3>
|
||||
<p><span class="shortcut">?</span><span class="description">This menu</span></p>
|
||||
<p><span class="shortcut">j</span><span class="description">Next Queet</span></p>
|
||||
<p><span class="shortcut">k</span><span class="description">Previous Queet</span></p>
|
||||
|
||||
<h3>Disable</h3>
|
||||
<p>Keyboard shortcuts can be turned off on <a href="{instance-url-with-protocol}settings/qvitter">the Qvitter settings page</a>.</p>
|
||||
@@ -5,11 +5,11 @@ direction this instance is going, you are free to move to another instance or st
|
||||
You will still be able to follow and be followed (and blocked) by users on this instance.</p>
|
||||
|
||||
<p>In constrast to the top-down authority of commercial social media, this creates a kind
|
||||
of flat power structure. We are enabled to protect eachother from harassment and opression,
|
||||
but without censorship.</p>
|
||||
of flat power structure. We are enabled to protect eachother from harassment and oppression,
|
||||
but without centralized censorship.</p>
|
||||
|
||||
<p>On this instance, users who harass others will be removed. We also take a strong stance
|
||||
against e.g. racism, sexism, ableism, homo- and transphobia. Such expressions make the
|
||||
<p>On this instance, users who harass others will be removed. We also take a strong stance
|
||||
against e.g. racism, sexism, ableism, antisemitism, homo- and transphobia. Such expressions make the
|
||||
site unsafe for other users, and in practice limit their freedom of speech.</p>
|
||||
|
||||
<p>The Public Timeline is considered an especially sensitive place. It is what new users see,
|
||||
@@ -20,8 +20,12 @@ If you are excluded from the public timeline, you can still use all other featur
|
||||
site just like any other user.</p>
|
||||
|
||||
<p>Advertising and commercial entities are not allowed on this instance. We are completely
|
||||
non-profit and all our expenses are payed for by donations from individuals.
|
||||
<a href="mailto:{instance-email}">We can help you</a> start your own GNU social instance
|
||||
non-profit and all our expenses are payed for by donations from individuals.
|
||||
<a href="mailto:{instance-email}">We can help you</a> start your own GNU social instance
|
||||
if your intention is commercial.</p>
|
||||
|
||||
<p>All content on this site is licensed with <a href="{instance-license-url}">{instance-license-title}</a>.</p>
|
||||
|
||||
<p>Each user is responsible for the content they submit. If you have any questions
|
||||
about something posted on this instance, contact the user in question first. As a last resort you
|
||||
can email the <a href="mailto:{instance-email}">admins</a>.</p>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<p>Otras «Preguntas frecuentes» y wikis de GNU social (antiguo StatusNet):<br>
|
||||
<a href="https://wiki.loadaverage.org/gnusocial/begin_to_be_social">https://wiki.loadaverage.org/gnusocial/begin_to_be_social</a> (en inglés)<br>
|
||||
<a href="http://wiki.gnusocial.de">http://wiki.gnusocial.de</a> (en alemán)</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h2 id="faq-table-of-contents">Tabla de contenido</h2>
|
||||
<ul>
|
||||
<li><a href="#faq-1">¿Qué es {instance-name}?</a></li>
|
||||
@@ -30,17 +30,17 @@
|
||||
<li><a href="#faq-21">Cómo citar conversaciones o partes de ellas</a></li>
|
||||
<li><a href="#faq-22">Cómo seguir frases de búsqueda y etiquetas (hashtags)</a></li>
|
||||
<li><a href="#faq-23">¿Por qué mi Repetición/Requeet no aparece en otros nodos?</a></li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<!-- 1 -->
|
||||
<h2 id="faq-1">¿Qué es {instance-name}? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>{instance-name} es uno de muchos nodos de GNU social (antiguo StatusNet).</p>
|
||||
<p>{instance-name} es un proyecto que usa el sistema de GNU social combinado con una interfaz gráfica familiar (IGU).</p>
|
||||
<p>El original de la IGU de GNU social está disponible como <em>Classic {instance-name} / {instance-name} Clásico</em>; se puede elegir haciendo clic en tu avatar en la cabecera (parte superior derecha).</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 2 -->
|
||||
<h2 id="faq-2">¿Qué son GNU social (antiguo StatusNet) y la Federación? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>GNU social, anteriormente llamado StatusNet, es una plataforma de microblogueo descentralizada.</p>
|
||||
@@ -54,33 +54,33 @@
|
||||
<p class="indent">@{nickname}@{instance-url}</p>
|
||||
<p>Si sigues a otro usuario, o el usuario está en la misma instancia que tú, puedes omitir la parte <em>@instancia.org</em> y simplemente utilizar la dirección corta:</p>
|
||||
<p class="indent">@usuario</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 3 -->
|
||||
<h2 id="faq-3">Cómo cambiar la imagen de perfil (avatar) <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>En {instance-name} Nuevo ve a:</p>
|
||||
<p class="indent">Tu imagen en la cabecera (superior derecha) → Editar perfil → icono de la cámara en la parte superior de tu avatar</p>
|
||||
<p>Utiliza las teclas «+» y «-» para acercar y alejar. Recorta la imagen arrastrándola con el ratón.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 4 -->
|
||||
<h2 id="faq-4">¿Por qué no puedo encontrar ninguna «aplicación {instance-name}» en Google Play Store o App Store de Apple? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>El nombre de la red es «GNU social» (antiguamente «StatusNet»), así que lo que quieres es una aplicación GNU social o StatusNet.</p>
|
||||
<p>Recuerda, {instance-name} es sólo una instancia en la federación de GNU social.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 5 -->
|
||||
<h2 id="faq-5">¿Qué clientes hay para GNU social/{instance-name}? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Puedes encontrar información sobre los clientes y los enlaces para la descarga aquí:<br>
|
||||
<a href="http://federation.skilledtests.com/Statusnet_clients.html">http://federation.skilledtests.com/Statusnet_clients.html</a><br>
|
||||
<a href="http://wiki.gnusocial.de/gnusocial:clients">http://wiki.gnusocial.de/gnusocial:clients</a> (en alemán)</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Clientes de Android</h3>
|
||||
<p><em>— Andstatus</em> (en desarrollo activo por <a href="https://loadaverage.org/andstatus">@andstatus@loadaverage.org</a>)<br>
|
||||
<em>tiene una formidable representación de las conversaciones como un árbol jerárquico<br>
|
||||
@@ -95,32 +95,32 @@ mensajes de gran tamaño se puedes abrir a través del navegador web</em></p>
|
||||
— <em>Zwitscher</em><br>
|
||||
— <em>Twydroid (software no libre)</em><br>
|
||||
Algunos clientes de Android para Twitter (es posible que características como el envío de Mensajes Directos o carga de imágenes no funcionen).</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Clientes de iPhone</h3>
|
||||
<p>— <em>Neustatus</em><br>
|
||||
— <em>Mayo</em>, <em>Mayonnaise</em><br>
|
||||
— <em>Meteoric</em> (software no libre, tiene bugs)</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Clientes de Windows</h3>
|
||||
<p>— <em>Tweetdeck 0.38-2</em> (software no libre) (última versión antes de Twitter se hizo cargo de TweetDeck) es adecuado para las funciones básicas.<br>
|
||||
Descarga: <a hrwf="http://www.oldversion.com/windows/download/tweetdeck-0-38-2">http://www.oldversion.com/windows/download/tweetdeck-0-38-2</a><br>
|
||||
Instrucciones: <a href="http://qttr.at/dmm">http://qttr.at/dmm</a>, <a href="http://qttr.at/dmm">http://qttr.at/dmn</a><br>
|
||||
— <em>Qwit</em> (Descarga: <a href="https://code.google.com/p/qwit/">https://code.google.com/p/qwit/</a>)<br>
|
||||
Clientes de Twitter (características como el envío de Mensajes Directos o carga de imágenes no funcionan)</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Clientes de Mac OSX</h3>
|
||||
<p>— <em>Tweetdeck 0.38-2</em> (software no libre) Descarga: <a href="http://www.oldversion.com/mac/tweetdeck/">http://www.oldversion.com/mac/tweetdeck/</a> Instrucciones: véase más arriba.</p>
|
||||
|
||||
|
||||
<h3>Clientes de GNU/Linux</h3>
|
||||
<p>— <em>Choqok</em><br>
|
||||
— <em>Hotot</em> (utiliza 0.9.7.32, esa es la versión que viene con Debian Wheezy)<br>
|
||||
— <em>Heybuddy</em><br>
|
||||
— más: <a href="http://federation.skilledtests.com/Statusnet_clients.html">http://federation.skilledtests.com/Statusnet_clients.html</a></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 6 -->
|
||||
<h2 id="faq-6">¿Dónde está el acortador de URL? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
En {instance-name} Nuevo:</p>
|
||||
@@ -133,9 +133,9 @@ En {instance-name} Clásico:</p>
|
||||
- URL más largo que 30<br>
|
||||
- Texto más largo que 139<br>
|
||||
Captura de pantalla: <a href="https://quitter.se/attachment/710078">https://quitter.se/attachment/710078</a></p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 7 -->
|
||||
<h2 id="faq-7">Cómo establecer preferencias de correo electrónico <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>En {instance-name} Nuevo ve a:</p>
|
||||
@@ -146,20 +146,20 @@ Captura de pantalla: <a href="https://quitter.se/attachment/710078">https://quit
|
||||
- Envíame un correo electrónico cuando alguien me envía un mensaje privado.<br>
|
||||
- Envíame un correo electrónico cuando alguien me envía un «@-reply».<br>
|
||||
- Permite a los amigos que me empujan y envíame un correo electrónico.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 8 -->
|
||||
<h2 id="faq-8">{instance-name} Nuevo y {instance-name} Clásico <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p><em>{instance-name} Nuevo</em> es la interfaz de usuario predeterminada. Visualmente es muy similar a otros servicios de microblogueo comerciales bien conocidos. Su nombre técnico es «Qvitter». En las discusiones, «Qvitter» y «{instance-name} Nuevo» pueden significar la misma cosa, pero «Qvitter» se refiere principalmente al software y «{instance-name} Nuevo» se refiere a la instalación del software Qvitter en {instance-name}.</p>
|
||||
<p><em>{instance-name} Clásico</em> usa la interfaz canónica de GNU social/StatusNet. En este momento algunos ajustes y características (p.ej., la creación de un grupo) tienen que hacerse en {instance-name} Clásico porque no están implementados en {instance-name} Nuevo.</p>
|
||||
<p>Para cambiar al {instance-name} Clásico ve a:</p>
|
||||
<p class="indent">Tu imagen en la cabecera (superior derecha) → Classic {instance-name}</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 9 -->
|
||||
<h2 id="faq-9">¿Qué son esas tres líneas temporales de {instance-name} Nuevo? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Hay tres líneas temporales que muestran noticias diferentes (según sus fuentes):
|
||||
@@ -169,10 +169,10 @@ Todas noticias de las personas que sigues (no sólo las que mandan a la gente cu
|
||||
Todas noticias publicadas por cuentas de tu servidor {instance-name}.</p>
|
||||
<p><strong>Toda la red conocida:</strong><br>
|
||||
No sólo todas publicaciones de la Línea temporal pública, sino también todas las de la gente en todas otras instancias de la federación de GNU social/StatusNet que son seguidas por al menos un usuario de tu servidor {instance-name} (es decir, las cuentas conocidas por {instance-name}, véase más arriba <a href="#faq-2">¿Qué es la Federación?</a>).</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 10 -->
|
||||
<h2 id="faq-10">Cómo gestionar las solicitudes de seguidores <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Generalmente quieres mantener la configuración predeterminada:</p>
|
||||
@@ -181,19 +181,19 @@ No sólo todas publicaciones de la Línea temporal pública, sino también todas
|
||||
<p>Si deseas cambiar esta configuración de {instance-name} Nuevo ve a:</p>
|
||||
<p class="indent">Tu imagen en la cabecera (superior derecha) → Configuración → Perfil</p>
|
||||
<p><em>(1): Cambia a "Pregúntame primero" y recibirás una notificación por correo electrónico cuando alguien quiera seguirte. Deja la solicitud de suscripción a la espera hasta que la confirmes o rechaces. (Pero esto todavía no funciona en {instance-name} Nuevo, así que ten cuidado con este ajuste.)</em></p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 11 -->
|
||||
<h2 id="faq-11">¿Puedo borrar mi cuenta de {instance-name}? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Puedes borrar tu cuenta, pero todas tus publicaciones se borrarán de {instance-name} también — y esto romperá hilos de conversación. Si restauras tu cuenta en otra instancia, es mejor cambiar el nombre de tu cuenta de {instance-name} a algo como "MiCuentaSeCambióAFragdev" en lugar de eliminarla.</p>
|
||||
<p>Para borrar tu cuenta ve a:</p>
|
||||
<p class="indent">Tu imagen en la cabecera (superior derecha) → Configuración → Perfil → Eliminar cuenta (caja derecha)</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 12 -->
|
||||
<h2 id="faq-12">Cómo conectar tu cuenta de {instance-name} con tu cuenta de Twitter <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Puedes enviar tus notificaciones a Twitter.</p>
|
||||
@@ -201,10 +201,10 @@ No sólo todas publicaciones de la Línea temporal pública, sino también todas
|
||||
<p class="indent">Tu imagen en la cabecera (superior derecha) → Configuración → Twitter</p>
|
||||
<p>Se te remite a Twitter y tienes que autorizar {instance-name} para utilizar tu cuenta de Twitter.</p>
|
||||
<p><em>Según informes de usuarios esto no siempre funciona en primera o segunda vez. En este caso, vuelve a intentarlo otra vez más tarde. La causa del problema puede estar del lado de Twitter. Tu navegador no debe bloquear JavaScript o Cookies.</em></p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 13 -->
|
||||
<h2 id="faq-13">Cómo escribir Mensajes Directos <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>En el momento de redactar esto, los Mensajes Directos sólo se admiten en {instance-name} Clásico (Mensajes en el menú de la izquierda).</p>
|
||||
@@ -213,26 +213,26 @@ No sólo todas publicaciones de la Línea temporal pública, sino también todas
|
||||
<p>Nota:<br>
|
||||
- Enviar MDs sólo funciona dentro de la misma instancia ({instance-name} en este caso)<br>
|
||||
- Para enviar MDs es necesario que os sigáis ambos mutuamente</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 14 -->
|
||||
<h2 id="faq-14">Favoritos y Repeticiones/Requeets <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>En las tres líneas temporales puedes hacer clic en una noticia para expandirla y ver quién la ha marcado como favorita o repetido.</p>
|
||||
<p>(Puedes configurar <a href="#faq-7"><em>Notificaciones de Correo Electrónico</em></a> para que te notifique cuando tus notas han sido marcada como favorita).</p>
|
||||
<p>Favs y Repeticiones/Requeets se parecen a esto en {instance-name} Nuevo: <a href="http://qttr.at/du6">http://qttr.at/du6</a> y a esto en {instance-name} Clásico: <a href="http://qttr.at/du6">http://qttr.at/du5</a></p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 15 -->
|
||||
<h2 id="faq-15">¿Qué significa la opción «Mis amigos en {instance-name}»? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>En {instance-name} Clásico hay una opción para enviar noticias a «Mis amigos en {instance-name}». Esta opción impide que tu noticia se envíe a toda la federación. Solamente será visible sólo para tus seguidores en {instance-name}.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 16 -->
|
||||
<h2 id="faq-16">Grupos <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<h3>Grupos públicos</h3>
|
||||
@@ -244,27 +244,27 @@ No sólo todas publicaciones de la Línea temporal pública, sino también todas
|
||||
<a href="http://www.skilledtests.com/wiki/List_of_federated_Statusnet_groups">http://www.skilledtests.com/wiki/List_of_federated_Statusnet_groups</a></p>
|
||||
<p>Para crear un grupo ve a:</p>
|
||||
<p class="indent"><a href="{instance-url-with-protocol}groups">{instance-url-with-protocol}groups</a> → Crear grupo nuevo</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Grupos privados</h3>
|
||||
<p>Un administrador de grupo tiene la opción declararlo privado. Esto significa que:</p>
|
||||
<p>1) los miembros nuevos deben ser aprobados por el administrador/los administradores, y</p>
|
||||
<p>2) todas las noticias son privadas.</p>
|
||||
<p>Es decir, las noticias del grupo son visibles solamente a los miembros del grupo (no aparecen en la Línea temporal pública tampoco), y no es posible para usuarios de otras instancias ser miembro de un grupo privado en {instance-name}.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 17 -->
|
||||
<h2 id="faq-17">Listas <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Las listas están disponibles sólo en {instance-name} Clásico. Debido a fusiones de características en GNU social las listas funcionan, pero son un poco desordenadas de gestionar.</p>
|
||||
|
||||
|
||||
<h3>Crear listas</h3>
|
||||
<p>El obstáculo principal con listas en {instance-name} es crear una nueva. Después de su creación puedes gestionarla y añadir personas de {instance-name} y de las instancias remotas en la página de la lista (véase más adelante).</p>
|
||||
<p>Para <em>iniciar</em> una lista en {instance-name} Clásico lo mejor es navegar a través de las listas de suscripción —«Siguiendo» y «Seguidores»— de alguien que tiene una cuenta en {instance-name}, <em>no en una instancia remota</em>. En el último caso, no puedes agregar personas de sus listas de suscripción a tu lista, es decir, crear una lista global.</p>
|
||||
<p>En ambas listas de suscripción —«Siguiendo» y «Seguidores»— encontrarás debajo de cada persona una pequeña caja con un símbolo de editar. Como aparecen en estas listas, no es problemático si tienen su cuenta en {instance-name} o en una instancia remota. Haz clic en ese símbolo y escribe el nombre de tu lista. Recibirás un mensaje de error, pero no importa, simplemente haz clic en «ok» y actualiza la página. La lista se ha creado con éxito y ahora se muestra en la columna a la izquierda.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Gestionar las listas</h3>
|
||||
<p>Para gestionar tu lista, ve a {instance-name} Clásico y abre la lista haciendo clic en su nombre en la columna a la izquierda. En su página, haz clic en «Editar» y se abre un menú.</p>
|
||||
<p>En la parte inferior —«Agregar o quitar a la gente»— puedes buscar cada persona conocida por {instance-name} desde la <em>Toda la red conocida</em> (véase arriba <a href="#faq-2">¿Qué es la Federación?</a>) por su nombre y añadirla a la lista. (Esto no es posible antes de la creación de la lista cuando la persona solamente aparece en las listas de suscripción de personas en instancias remotas. Véase más arriba). Asimismo, puedes quitar aquí a la persona de la lista.</p>
|
||||
@@ -278,29 +278,30 @@ No sólo todas publicaciones de la Línea temporal pública, sino también todas
|
||||
<p class="indent">"Deleting this tag will permanantly remove all its subscription and membership records. Do you still want to continue?" Yes / No</p>
|
||||
<p>Que significa: «Eliminar esta etiqueta supone borrar permanentemente todas sus suscripciones e interacciones. ¿Quieres continuar?» Sí / No</p>
|
||||
<p>Selecciona «Sí» ("Yes"), lo que te redirecciona a la línea temporal Inicio. Pincha en tu Perfil y la lista se habrá ido y tampoco se podrá encontrar en tus listas.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 18 -->
|
||||
<h2 id="faq-18">Cómo bloquear <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Para bloquear a un usuario de {instance-name} donde tienes tu cuenta, ve a su perfil en {instance-name} Clásico</p>
|
||||
<p class="indent">{instance-url-with-protocol}<nombre de usuario></p>
|
||||
<p>y haz clic en «Bloquear» por debajo de su descripción de perfil.</p>
|
||||
<p>No recomendamos el bloqueo de la gente de otros servidores de GNU social en general porque todavía hay problemas con esta característica.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 19 -->
|
||||
<h2 id="faq-19">Cómo seguir a alguien de otro nodo/servidor <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>En {instance-name} Nuevo:</p>
|
||||
<p>Al hacer clic en {instance-name} Nuevo en el apodo del usuario de una instancia remota eres llevado a una pequeña ventana de perfil que muestra la dirección remota completa, p.ej., @blabla@status.vinilox.eu. Haz clic en el botón «Seguir». Eso debería ser todo.</p>
|
||||
<p>En {instance-name} Clásico:</p>
|
||||
<p>En {instance-name} Clásico eres reenviado al perfil del usuario en la instancia remota (que puede diferir en el diseño y tema de {instance-name} Clásico). Busca el botón «Seguir» / «Suscribirse» (por lo general en la parte superior derecha). Una caja de la suscripción se abre y se te pide que introduzcas tu propia "dirección webfinger", es decir, {nickname}@{instance-url}. Suscríbete y se te redirigirá a tu página de {instance-name} Clásica donde tienes que confirmar la suscripción.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>Manualmente:</p>
|
||||
<p>En caso de que sepas el apodo del usuario y el nombre de la instancia remota, puedes iniciar el proceso de seguir a alguien de otro nodo por visitar <a href=" {instance-url-with-protocol}/main/ostatussub">{instance-url-with-protocol}/main/ostatussub</a>.</p>
|
||||
|
||||
|
||||
|
||||
<!-- 20 -->
|
||||
<h2 id="faq-20">Cómo gestionar la visibilidad de tus publicaciones <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Hay varias maneras de hacer noticias visibles solamente a personas seleccionadas, no al público. <strong>Ninguno de ellos funciona en {instance-name} Nueva todavía.</strong> </p>
|
||||
@@ -313,9 +314,9 @@ No sólo todas publicaciones de la Línea temporal pública, sino también todas
|
||||
<p>d. Envía el aviso a un grupo público y cierra la cerradura a la derecha del menú desplegable bajo el campo del mensaje. La noticia será visible solamente para los miembros del grupo. (Aunque en el momento de redactar esto no funciona en {instance-name}. El mensaje será visible a todos.)</p>
|
||||
<p><em>(Nota a d: Asegúrate de no dejar «Todos» o «Mis colegas en {instance-name}» seleccionado, o de lo contrario tu mensaje irá a las líneas temporales de cada usuario de {instance-name}, que no es lo que quieres si cierras la cerradura)</em></p>
|
||||
<p><em>(Nota a d: El método de cerradura solamente está disponible en {instance-name} Clásico. No hay ninguna característica de cerradura en {instance-name} Nuevo o cualquier otro cliente conocido en el momento de redactar.)</em></p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 21 -->
|
||||
<h2 id="faq-21">Cómo citar conversaciones o partes de ellas <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>A veces, en un blog o correo electrónico, no quieres citar solamente una noticia, sino toda la conversación. Cada noticia, cada respuesta, y cada conversación tiene su propia URL, y las maneras de encontrarlas difieren ligeramente en {instance-name} Clásico y en {instance-name} Nuevo.</p>
|
||||
@@ -323,10 +324,10 @@ No sólo todas publicaciones de la Línea temporal pública, sino también todas
|
||||
<p>Haz clic en la fecha de una noticia (o «Detalles» si la has expandido). Esto muestra la página de la noticia con la conversación expandida.</p>
|
||||
<p>En {instance-name} Clásico:</p>
|
||||
<p>Haz clic en la fecha de cualquier noticia. El mensaje reaparece en una página separada. Haz clic en «En contexto». Toda la conversación en la que esta noticia es involucrado es mostrado en una nueva página, con la noticia seleccionada en la parte superior o más abajo.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 22 -->
|
||||
<h2 id="faq-22">Cómo seguir frases de búsqueda y etiquetas (hashtags) <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>Similar al suscribirse a las personas o grupos puedes suscribirte a (o: seguir) etiquetas (hashtags) y frases de búsqueda. Las noticias que contienen estos aparecerán entonces en tu Línea temporal («Inicio»).</p>
|
||||
@@ -338,16 +339,14 @@ No sólo todas publicaciones de la Línea temporal pública, sino también todas
|
||||
hashtags: <a href="{instance-url-with-protocol}{nickname}/tag-subscriptions">{instance-url-with-protocol}{nickname}/tag-subscriptions</a><br>
|
||||
palabras y frases de búsqueda: <a href="{instance-url-with-protocol}{nickname}/search-subscriptions">{instance-url-with-protocol}{nickname}/search-subscriptions</a></p>
|
||||
<p>En esas páginas puedes gestionar sus suscripciones, es decir, añadir más frases y etiquetas o dejar de seguirlos.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 23 -->
|
||||
<h2 id="faq-23">¿Por qué mi Repetición/Requeet no aparece en otros nodos? <a href="#faq-table-of-contents">Top</a></h2>
|
||||
<p>En las últimas versiones de GNU social, las Repeticiones/Requeets no son enviadas a tus seguidores en nodos remotos. Esto fue posible en StatusNet hace algún tiempo, pero esta característica se ha eliminado debido a un problema de seguridad. Los desarrolladores de GNU social están trabajando en una solución. Mientras tanto, si quieres que tu Repetición/Requeet se envíe a otros nodos, puedes hacer una «repetición manual», es decir, escribe RQ @<nombre de usuario> y copia y pega la noticia en esta nueva.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p class="faq-credits"><em>Traducción del inglés al español por <a href="https://quitter.se/simsa01">@simsa01@quitter.se</a>. Revisión de <a href="https://quitter.es/moshpirit">@moshpirit@quitter.es</a>, <a href="https://quitter.se/larjona">@larjona@quitter.se</a> y <a href="https://quitter.no/efedoso">@efedoso@quitter.no</a>. (2015)</em></p>
|
||||
<p><em>El original en inglés fue elaborado en 2014 por <a href="https://quitter.se/simsa01">@simsa01@quitter.se</a> y <a href="https://quitter.se/mcscx">@mcscx@quitter.se</a>.</em></p>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<p>{instance-name} no es un servicio y tú no eres un cliente aquí. Somos una pequeña parte de un
|
||||
cambio social mayor, creando una gran comunidad descentralizada. Esto significa que no tenemos que
|
||||
ser neutrales sobre el contenido de este nodo de GNU Social. Si no te gusta el camino que el nodo
|
||||
está llevando, eres libre de cambiarte a otro nodo o crear el tuyo propio. Podrás continuar siguiendo
|
||||
y siendo seguido (o bloqueado) por usuarios de este nodo.</p>
|
||||
|
||||
<p>Frente al modelo vertical de jerarquía de las redes comerciales, éste crea una estructura de poder
|
||||
horizontal. Podemos proteger a los demás de acoso y opresión, pero sin centralizar la censura.</p>
|
||||
|
||||
<p>En este nodo, los usuarios que acosen a otros serán eliminados. Tendremos también una postura
|
||||
estricta contra el racismo, el sexismo, la discriminación contra personas discapacitadas, la homofobia
|
||||
y la transfobia. Tales comportamientos hacen el sitio inseguro para otros usuarios y, en la práctica,
|
||||
limita su libertad de expresión.</p>
|
||||
|
||||
<p>La Línea Temporal Pública es considerada un lugar especialmente sensible. Es lo que los nuevos
|
||||
usuarios ven, y todos los usuarios registrados van a ver los mensajes publicados ahí. Los moderadores
|
||||
pueden excluir a usuarios de aparecer en la línea temporal pública en cualquier momento, sin previo
|
||||
aviso, temporal o permanentemente. Considera publicar en la línea temporal como un privilegio, no como
|
||||
un derecho. Si eres excluido de la línea temporal pública, todavía dispones de otras opciones en el
|
||||
sitio como cualquier otro usuario.</p>
|
||||
|
||||
<p>Publicidad y entidades comerciales no son permitidas en este nodo. No tenemos ningún ánimo de lucro
|
||||
y nuestros gastos son pagados por donaciones de personas. <a href="mailto:{instance-email}">Podemos
|
||||
ayudarte</a> a montar tu propio nodo de GNU Social si tu intención no es comercial.</p>
|
||||
|
||||
<p>Todos los contenidos de este sitio están bajo licencia <a href="{instance-license-url}">{instance-license-title}</a></p>
|
||||
|
||||
<p>Cada usuario es responsable del contenido que sube. Si tienes dudas sobre algo publicado en este
|
||||
nodo, contacta primero con el usuario en cuestión. Como último recurso puedes escribir un correo
|
||||
electrónico a los <a href="mailto:{instance-email}">administradores</a>.</p>
|
||||
@@ -0,0 +1,290 @@
|
||||
<p id="top">Ica guidotexto pri {instance-name} esas por nova uzeri partikulare. Olu koncentresas pri quale procedar, sen expozar troa detali. Por preciza teknikala questioni (exemple, quale instalar exemplero di GNU Social) pliz questionez ye la grupi <a href="https://status.vinilox.eu/group/gnusocial">!gnusocial</a> e <a href="http://sn.postblue.info/group/sn">!sn</a>, o ye la publika tempolineo di {instance-name}. Vu povas anke trovar teknikala informi ye <a href="http://federation.skilledtests.com/">http://federation.skilledtests.com/</a></p>
|
||||
<p>La serio de punti sequas cirkume la frequeso di la questioni quin nova uzeri questionabas.</p>
|
||||
<p>Altra ofta questioni e wiki-i pri GNU Social:<br>
|
||||
<a href="https://wiki.loadaverage.org/gnusocial/begin_to_be_social">https://wiki.loadaverage.org/gnusocial/begin_to_be_social</a><br>
|
||||
<a href="http://wiki.gnusocial.de">http://wiki.gnusocial.de</a> (Germane)</p>
|
||||
|
||||
<h2 id="faq-table-of-contents">Tabelo di la kontenajo</h2>
|
||||
<ul>
|
||||
<li><a href="#faq-1">Quo esas {instance-name}?</a></li>
|
||||
<li><a href="#faq-2">Quo esas GNU Social e la Federo?</a></li>
|
||||
<li><a href="#faq-3">Quale krear profil-imajo</a></li>
|
||||
<li><a href="#faq-4">Pro quo me povas trovar nula "{instance-name}-aplikaciono" ye la Google Play Store o ye la App Store di Apple?</a></li>
|
||||
<li><a href="#faq-5">Qua klientin esas por GNU Social o {instance-name}?</a></li>
|
||||
<li><a href="#faq-6">Ube esas la URL-plukurtigilo?</a></li>
|
||||
<li><a href="#faq-7">Quale ajustar preferaji pri la e-posto</a></li>
|
||||
<li><a href="#faq-8">Nova {instance-name} e Klasika {instance-name}</a></li>
|
||||
<li><a href="#faq-9">Quo esas ta tri tempolinei ye Nova {instance-name}?</a></li>
|
||||
<li><a href="#faq-10">Quale jerar sequo-demandi</a></li>
|
||||
<li><a href="#faq-11">Ka me povas efacar mea konto ye {instance-name}?</a></li>
|
||||
<li><a href="#faq-12">Quale konektar vua konto ye {instance-name} kun vua konto ye Twitter</a></li>
|
||||
<li><a href="#faq-13">Quale skribar direta mesaji</a></li>
|
||||
<li><a href="#faq-14">Favorati e repeti</a></li>
|
||||
<li><a href="#faq-15">Quon la opciono "Mea kolegi ye {instance-name}" facas?</a></li>
|
||||
<li><a href="#faq-16">Grupi</a></li>
|
||||
<li><a href="#faq-17">Listi</a></li>
|
||||
<li><a href="#faq-18">Quale blokusar</a></li>
|
||||
<li><a href="#faq-19">Quale sequar ulu ye altra exemplero</a></li>
|
||||
<li><a href="#faq-20">Quale jerar la videbleso di vua mesaji</a></li>
|
||||
<li><a href="#faq-21">Quale citar konversi o parti di li</a></li>
|
||||
<li><a href="#faq-22">Quale sequar klefovorti e hashtagi</a></li>
|
||||
<li><a href="#faq-23">Pro quo mea repeto ne aparas ye altra exempleri?</a></li>
|
||||
</ul>
|
||||
|
||||
<!-- 1 -->
|
||||
<h2 id="faq-1">Quo esas {instance-name}? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>{instance-name} esas un ek multa exempleri di GNU Social. </p>
|
||||
<p>{instance-name} esas projeto uzanta la sistemo GNU Social, kombinita kun familiara uzer-interfacio (UI).</p>
|
||||
<p>L'originala UI di GNU Social esas disponebla kom "Klasika {instance-name}", selektebla de la profil-imajo di vua titulo-bendo (supra dextro).</p>
|
||||
|
||||
<!-- 2 -->
|
||||
<h2 id="faq-2">Quo esas GNU Social e la Federo? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>GNU Social esas descentraligita mikroblogo-platformo.</p>
|
||||
<p>Uzeri di ula exemplero (o: servado) povas sequar, esar sequata da, e komunikar kun uzeri di irga altra exemplero.</p>
|
||||
<p>Altra exempleri esas, exemple, <a href="https://loadaverage.org/">loadaverage.org</a>, <a href="http://status.vinilox.eu/">status.vinilox.eu</a>, <a href="http://micro.fragdev.com/">micro.fragdev.com</a>, <a href="https://gnusocial.de/">gnusocial.de</a>, <a href="https://indy.im/">indy.im</a>, <a href="https://quitter.se/">quitter.se, <a href="http://rainbowdash.net/">rainbowdash.net</a>, e. c. La nuna nombro de mikroblog-exempleri uzanta la softwaro GNU Social esas probable cirkume 50, {instance-name} esanta un ek oli. Nam omni uzas la sama softwaro (GNU Social) e protokolo de transmiso (OStatus), oli povas interkomunikar tote quale servili de e-posto, mem se oli esas nedependanta e funcionigata da diferanta firmi.</p>
|
||||
<p>Konekti inter exempleri esas fondita da uzeri sequanta l'una e l'altra. Tra tala sequi omna ta exempleri povas (adminime principe) esar unionita aden un kompozita strukturo o reto de su-kontenata exempleri. Ico nomesas la Federo. GNU Social esas strukturigita ulamaniere ke bezonas nur un sequo di uzero <strong>a</strong> de exemplero <strong>A</strong> vers uzero <strong>b</strong> de exemplero <strong>B</strong> por videbligar <strong>b</strong> ad omnu ye exemplero <strong>A</strong> tra <em>Tota retaro</em>. (Videz sube pri la <a href="#faq-9">tri tempolinei</a>.) La tota retaro esas la plu vasta reto de exempleri quale vidata da {instance-name}. Olu aspektas diferanta ye, exemple, loadaverage, nam ye loadaverage esas diferanta sequi vers altra exempleri kam ye {instance-name}. </p>
|
||||
<p>Esas nula centrala "unajo" di qua la paneo povus renversar la tota retaro. Se exemplero paneas o se l'administranti komencas facar kozi quin vu ne prizas, vu povas krear vua konto ye altra exemplero. Vu esos ankore ye la reto GNU Social ed ankore povos komunikar kun vua amiki ye GNU Social. Vu nur bezonos informar vua relati pri vua nova adreso.</p>
|
||||
<p>Adresi ye GNU Social aspektas tale:</p>
|
||||
<p class="indent">@uzero@exemplero.org</p>
|
||||
<p>Vua adreso esas:</p>
|
||||
<p class="indent">@{nickname}@{instance-url}</p>
|
||||
<p>Se vu sequas altra uzero, o se la uzero esas ye la sama exemplero, vu darfas omisar la parto …@instance.org e nur uzar la kurta adreso</p>
|
||||
<p class="indent">@uzero</p>
|
||||
|
||||
<!-- 3 -->
|
||||
<h2 id="faq-3">Quale krear profil-imajo <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Ye Nova {instance-name}, irez ye</p>
|
||||
<p class="indent">La profil-imajo di vua titulo-bendo (supra dextro) → Modifikar la profilo → Kamero-ikono super vua profil-imajo</p>
|
||||
<p>Uzez la butoni + e - por plugrandigar e plumikrigar. Rekortez la imajo per dragar olu per la mauso.</p>
|
||||
|
||||
<!-- 4 -->
|
||||
<h2 id="faq-4">Pro quo me povas trovar nula "{instance-name}-aplikaciono" ye la Google Play Store o ye la App Store di Apple? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>La reto nomesas "GNU Social" ed antee "StatusNet", do quon vu volas esas GNU-Social-aplikaciono o StatusNet-aplikaciono.</p>
|
||||
<p>(Memorez, ke {instance-name} esas nur un exemplero di la federo GNU Social.)</p>
|
||||
|
||||
<!-- 5 -->
|
||||
<h2 id="faq-5">Qua klientin esas por GNU Social o {instance-name}? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Vu povas trovar informajo pri klienti e ligili por deskargar hike:<br>
|
||||
<a href="http://federation.skilledtests.com/Statusnet_clients.html">http://federation.skilledtests.com/Statusnet_clients.html</a><br>
|
||||
<a href="http://wiki.gnusocial.de/gnusocial:clients">http://wiki.gnusocial.de/gnusocial:clients</a> (Germane)</p>
|
||||
<h3>Klienti por Android</h3>
|
||||
<p>— <em>Andstatus</em> (nun ageme developata da <a href="https://loadaverage.org/andstatus">@andstatus@loadaverage.org</a>)<br>
|
||||
<em>havas bonega konverso-vido kom hierarkiala arboro<br>
|
||||
Imajo-kargo ed expozo di imaj-atachuri<br>
|
||||
tro granda mesaji povas esar apertita tra reto-navigilo</em></p>
|
||||
<p>— <em>Mustard 0.3.5c</em> (Android 2.x - nuna) (multi preferas olu, probinda: GreyBubble-temo)<br>
|
||||
— <em>Mustard 0.4.1</em> (Android 3.x - nuna) (kelke experimentala nova aprocho kun nova aspekto)<br>
|
||||
— <em>Mustard{MOD}</em> (Android 3.x - nuna)<br>
|
||||
<em>Omna Mustard-i suportas geosituo, kargo ed expozo di imaj-atachuri, expozo di tro granda mesaji de exempleri kun plu granda signo-limito (apertez kom atachuro)</em></p>
|
||||
<p>— <em>Twidere</em><br>
|
||||
— <em>Seesmic 1.7.6</em> (uzez nur ica versiono!) (klozita fonto)<br>
|
||||
— <em>Zwitscher</em><br>
|
||||
— <em>Twydroid</em> (klozita fonto)<br>
|
||||
Kelka apta Twitter-klienti por Android (funcioni tala kam sendar direta mesaji od imajo-kargo forsan ne funcionos).</p>
|
||||
<h3>Klienti por iPhone</h3>
|
||||
<p>— <em>Neustatus</em><br>
|
||||
— <em>Mayo</em> anke konocata kom Mayonnaise <br>
|
||||
— <em>Meteoric</em> (pagenda, defektoza)</p>
|
||||
<h3>Klienti por Windows</h3>
|
||||
<p>— <em>Tweetdeck 0.38.2</em> (klozita fonto) (lasta versiono ante ke Twitter aquiris TweetDeck) esas apta por bazala funcioni.<br>
|
||||
Deskargar: <a href="http://www.oldversion.com/windows/download/tweetdeck-0-38-2">http://www.oldversion.com/windows/download/tweetdeck-0-38-2</a><br>
|
||||
Instrucioni: <a href="http://qttr.at/dmm">http://qttr.at/dmm</a> <a href="http://qttr.at/dmn">http://qttr.at/dmn</a><br>
|
||||
— <em>Qwit</em> (Deskargar: <a href="https://code.google.com/p/qwit/">https://code.google.com/p/qwit/</a>)<br>
|
||||
Twitter-klienti (funcioni tala kam sendar direta mesaji ed imajo-kargo ne funcionas)</p>
|
||||
<h3>Klienti por OS X</h3>
|
||||
<p>— <em>Tweetdeck 0.38.2</em> (klozita fonto) Deskargar: <a href="http://www.oldversion.com/mac/tweetdeck/">http://www.oldversion.com/mac/tweetdeck/</a> Instructioni: videz supere.<br>
|
||||
— Adium (Deskargar: <a href="https://adium.im/">https://adium.im/</a>)</p>
|
||||
<h3>Klienti por GNU/Linux</h3>
|
||||
<p>— <em>Choqok</em><br>
|
||||
— <em>Hotot</em> (uzez 0.9.7.32, ol esas la versiono qua esas provizita kun Debian Wheezy)<br>
|
||||
— <em>Heybuddy</em> <br>
|
||||
— pluo: <a href="http://federation.skilledtests.com/Statusnet_clients.html">http://federation.skilledtests.com/Statusnet_clients.html</a></p>
|
||||
|
||||
<!-- 6 -->
|
||||
<h2 id="faq-6">Ube esas la URL-plukurtigilo? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Ye Nova {instance-name}:
|
||||
<p class="indent">Ligili mustas esar plukurtigita manuale ante la sendo dil mesajo. La "URL ><"-butono plukurtigos irga URL-i glutinita o skribita aden la mesajo-feldo.
|
||||
<p>Ye Klasika {instance-name}:
|
||||
<p class="indent">Ligili esas plukurtigita automatale pos la sendo dil mesajo. L'ajusti dependas de la selekti dil uzero.<br>
|
||||
<br>
|
||||
Ajusti → URL<br>
|
||||
<br>
|
||||
Maxim bone uzez la sequanta ajusti:<br>
|
||||
- qttr.at<br>
|
||||
- URL plu longa kam 30<br>
|
||||
- Texto plu longa kam 139<br>
|
||||
Skreno-kapturo: <a href="http://quitter.se/attachment/710078">http://quitter.se/attachment/710078</a></p>
|
||||
|
||||
|
||||
<!-- 7 -->
|
||||
<h2 id="faq-7">Quale ajustar preferaji pri la e-posto <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Ye Nova {instance-name} irez ye</p>
|
||||
<p class="indent">La profil-imajo di vua titulo-bendo (supra dextro) → Ajusti → E-posto</p>
|
||||
<p>markizez konforme:<br>
|
||||
<em>— Sendar a me avizi pri nova sequi tra e-posto. <br>
|
||||
— Sendar a me e-letro kande ulu favoras mea mesajo. <br>
|
||||
— Sendar a me e-letro kande ulu sendas a me direta mesajo. <br>
|
||||
— Sendar a me e-letro kande ulu sendas a me "@-respondo". <br>
|
||||
— Darfar a mea amiki kudo-frapetar me e sendar a me e-letro. </em></p>
|
||||
|
||||
|
||||
<!-- 8 -->
|
||||
<h2 id="faq-8">Nova {instance-name} e Klasika {instance-name} <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Nova {instance-name} uzas la kustuma uzer-interfacio. Ol aspektas tre simila ad altra tre konocata komercala servadi de mikroblogo. Lua teknikala nomo esas "Qvitter". En diskuti "Qvitter" e "Nova {instance-name}" povas signifikar la sama kozo, ma "Qvitter" precipue referas a la softwaro e "Noa {instance-name}" referas al instaluro di la Qvitter-softwaro ye {instance-name}.</p>
|
||||
<p>Klasika {instance-name} esas la bazala uzer-interfacio di GNU Social. Cainstante kelka ajusti e funcioni (exemple, la kreo di grupo) mustas esar facita per Klasika {instance-name} nam oli ne esas ankore tote realigita ye Nova {instance-name}.</p>
|
||||
<p>Por swichar vers Klasika {instance-name} irez ye</p>
|
||||
<p class="indent">La profil-imajo di vua titulo-bendo (supra dextro) → Klasika {instance-name}</p>
|
||||
|
||||
|
||||
<!-- 9 -->
|
||||
<h2 id="faq-9">Quo esas ta tri tempolinei ye Nova {instance-name}? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Esas tri tempolinei qui montras diferanta mesaji (dependante de la fonti):</p>
|
||||
<p><strong>Tempolineo ("Hemo"):</strong><br>
|
||||
omna mesaji da la personi quin vu sequas (ne nur oli quin li sendas a personi quin vu anke sequas).</p>
|
||||
<p><strong>Publika tempolineo:</strong><br>
|
||||
omna mesaji publikigita da konti ye {instance-name}.</p>
|
||||
<p><strong>Tota retaro:</strong><br>
|
||||
ne nur omna mesaji di la publika tempolineo ma anke oli da omna personi ye altra ("fora") exempleri di la federo GNU Social e sequata da adminime un uzero ye {instance-name} (exemple, konti konocata da {instance-name}, videz supere <a href="#faq-2">Quo esas la Federo?</a>).</p>
|
||||
|
||||
|
||||
<!-- 10 -->
|
||||
<h2 id="faq-10">Quale jerar sequo-demandi <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Generale, vu deziros konservar la kustuma ajusti:</p>
|
||||
<p class="indent">yes por "lasar irgu sequar me" (1)</p>
|
||||
<p class="indent">no por "Igar aktualigi videbla nur por mea sequanti"</p>
|
||||
<p>Se vu reale deziras chanjar ica ajusti ye Nova {instance-name} irez ye: </p>
|
||||
<p class="indent">La profil-imajo di vua titulo-bendo (supra dextro) → Ajusti → Profilo</p>
|
||||
<p><em>(1): Chanjez por "Demandar a me unesme" e vu recevos e-postala avizo kande ulu deziros sequar vu. Olu lasas la sequo-demando vartanta til ke vu sive konfirmos sive refuzos olu. (Ma olu ne funcionas ye Nova {instance-name} ankore, do esez prudenta kun ica ajusto.)</em></p>
|
||||
|
||||
|
||||
<!-- 11 -->
|
||||
<h2 id="faq-11">Ka me povas efacar mea konto ye {instance-name}? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>You can delete your account, but all your notices will be deleted on {instance-name} as well – and this will break conversation threads. If you restore your account on another instance, it's better to rename your {instance-name} account to something like MyNickhasmovedtoFragdev instead of deleting it.</p>
|
||||
<p>To delete your account go to:</p>
|
||||
<p class="indent">Your header avatar (upper right) → Settings → Profile → Delete account (right column)</p>
|
||||
|
||||
|
||||
<!-- 12 -->
|
||||
<h2 id="faq-12">Quale konektar vua konto ye {instance-name} kun vua konto ye Twitter <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>You can forward your notices to Twitter.</p>
|
||||
<p>In New {instance-name}:</p>
|
||||
<p class="indent">Your header avatar (upper right) → Settings → Twitter</p>
|
||||
<p>You are forwarded to Twitter and have to authorise {instance-name} to use your Twitter account.</p>
|
||||
<p><em>According to user reports this doesn't always work on the first or second attempt. If it doesn't, try again later. The cause of the problem may be on Twitter's side. Your browser must not block Javascript or Cookies.</em></p>
|
||||
|
||||
|
||||
|
||||
<!-- 13 -->
|
||||
<h2 id="faq-13">Quale skribar direta mesaji <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Direct Messages are only supported in Classic {instance-name} at the time of writing (Messages in the left menu).</p>
|
||||
<p class="indent">Your header avatar (upper right) → Classic {instance-name} → Messages (left column)</p>
|
||||
<p>You can use apps like Mustard and Mayo to send DMs.</p>
|
||||
<p><em>Note:</em><br>
|
||||
- Direct Messaging only works within the same instance ({instance-name} in this case)<br>
|
||||
- to send DMs you need to mutually follow each other</p>
|
||||
|
||||
|
||||
<!-- 14 -->
|
||||
<h2 id="faq-14">Favorati e repeti <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
|
||||
<p>In all the three timelines you can click on a notice to expand it and see who has favored or repeated it.</p>
|
||||
<p>(You can setup <a href="#faq-7"><em>Email Notifications</em></a> to notify you when your notices have been fav'ed.)</p>
|
||||
<p>Favs and Repeats/Requeets look like this in New {instance-name}: <a href="http://qttr.at/du6">http://qttr.at/du6</a> and like this in Classic {instance-name}: <a href="http://qttr.at/du5">http://qttr.at/du5</a></p>
|
||||
|
||||
|
||||
<!-- 15 -->
|
||||
<h2 id="faq-15">Quon la opciono "Mea kolegi ye {instance-name}" facas? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>In Classic {instance-name}, there is an option to post to "My colleagues at {instance-name}". This will stop the notice from "federating". It will only be visible to your followers on {instance-name}.</p>
|
||||
|
||||
<!-- 16 -->
|
||||
<h2 id="faq-16">Grupi <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<h3>Public Groups</h3>
|
||||
<p>On {instance-name} you can create a group for nearly any topic, like Feminism, Football, FreeBSD. ("Nearly" because the laws in the country hosting the website may prohibit such things as slander and hate speech.)</p>
|
||||
<p>You can be a member of as many groups as you like. As group-member you can post to the whole group by attaching ! to the group name, e.g., <em>!feminism</em>, in the notice. All group members, whether or not they follow you, will get the notice in their Home Timelines. You follow and unfollow a group like you follow and unfollow a person. </p>
|
||||
<p>A list of groups <em>hosted on {instance-name}</em> can be found here:<br>
|
||||
<a href="{instance-url-with-protocol}groups">{instance-url-with-protocol}groups</a></p>
|
||||
<p>A list of groups <em>hosted also on remote instances</em> can be found here:<br>
|
||||
<a href="http://www.skilledtests.com/wiki/List_of_federated_Statusnet_groups">http://www.skilledtests.com/wiki/List_of_federated_Statusnet_groups</a></p>
|
||||
<p>To create a group go to:</p>
|
||||
<p class="indent"><a href="{instance-url-with-protocol}groups">{instance-url-with-protocol}groups</a> → Create new group</p>
|
||||
<h3>Private Groups</h3>
|
||||
<p>An admin of a group has the option to declare it private. This means:</p>
|
||||
<p>1) new members must be approved by the admin(s), and</p>
|
||||
<p>2) all notices are forced to be private.<br>
|
||||
That is, notices in the group are only visible to group members (they don't appear in the Public Timeline), and it is not possible for users of other instances to be members of a private group on {instance-name}.</p>
|
||||
|
||||
|
||||
<!-- 17 -->
|
||||
<h2 id="faq-17">Listi <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Lists are available only in Classic {instance-name}. Due to feature merges in GNU social they do work but are a bit messy to manage and delete.</p>
|
||||
<h3>Creating lists</h3>
|
||||
<p>The main hurdle with lists on {instance-name} is to create a new one. After its creation, you can manage it and add people from {instance-name} as well as from remote instances on its newly created page (see below).</p>
|
||||
<p>To start a list in Classic {instance-name} you best proceed by browsing through the subscription lists of someone who has an account on {instance-name}, not on a remote instance. In the latter case you will not be able to add people from their subscription lists to your list, i.e, create a list at all.</p>
|
||||
<p>In both subscription lists you'll find beneath each person listed a tiny box with an edit-symbol. As they show up in these lists, it's no longer problematic whether they have their account on {instance-name} or on a remote instance. Click on that symbol and type in the name of your list. You'll receive an error message, but don't mind, just click "ok" and refresh the page. The list has been successfully created and is now shown in the left hand side column.</p>
|
||||
<h3>Managing lists</h3>
|
||||
<p>To manage your list, go to your page in Classic {instance-name} and open the list by clicking on its name in the left column. On its page, click "Edit" and a menu opens.</p>
|
||||
<p>In the section "Add or remove people" below you can now search every person known to {instance-name} from the whole known network (see above <a href="#faq-2">What is the Federation?</a>) by name and add her to your list. (Which isn't possible prior to the creation of the list when the person appears only in subscription lists of people on remote instances. See above.) Likewise you can remove the person from the list here.</p>
|
||||
<p>In the upper section you can reword the list's name and give it a description that is displayed on the list's page. With the option "private" you can make the list invisible to other people on {instance-name}.</p>
|
||||
<h3>Deleting lists</h3>
|
||||
<p>To delete your lists, go to their directory, choose one, click "Edit", tick the box "Private", then click "Save". You'll get the option:</p>
|
||||
<p class="indent">"Setting a public tag as private will permanently remove all the existing subscriptions to it. Do you still want to continue?" Yes / No</p>
|
||||
<p>Click "Yes". You return to the Edit-page of the list. Now click "Delete". You'll get the option:</p>
|
||||
<p class="indent">"Deleting this tag will permanantly remove all its subscription and membership records. Do you still want to continue?" Yes / No</p>
|
||||
<p>Click "Yes" and you're forwarded to your Home timeline. Click your Profile, and the list is gone and neither to be found in your directory of lists.</p>
|
||||
|
||||
|
||||
|
||||
<!-- 18 -->
|
||||
<h2 id="faq-18">Quale blokusar <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>To block a {instance-name} user, go to their profile in Classic {instance-name}</p>
|
||||
<p class="indent">{instance-url-with-protocol}<username></p>
|
||||
<p>and click "block" below their profile desription</p>
|
||||
<p>We don't recommend blocking people from remote instances as there are still issues with this feature.</p>
|
||||
|
||||
|
||||
<!-- 19 -->
|
||||
<h2 id="faq-19">Quale sequar ulu ye altra exemplero <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>In New {instance-name}:</p>
|
||||
<p>When you click a remote nickname in New {instance-name} you are brought to a small profile window showing the full remote address, e.g., @blabla@status.vinilox.eu. Click the button "Follow". That should be all. </p>
|
||||
<p>In Classic {instance-name}:</p>
|
||||
<p>In Classic {instance-name} you're forwarded to the remote instance's user profile (which may differ in layout and theme from Classic {instance-name}). Look for the Subscribe-button (usually in the upper right). A subscription box opens and you are prompted to enter your own "webfinger address", i.e., {nickname}@{instance-url} Subscribe and you are redirected to your Classic {instance-name} page where you have to confirm the subscription.</p>
|
||||
|
||||
|
||||
<!-- 20 -->
|
||||
<h2 id="faq-20">Quale jerar la videbleso di vua mesaji <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>There are several ways to make notices visible only to selected people, not to the public. <strong>None of them work in New {instance-name} yet.</strong></p>
|
||||
<p>All four methods only work within the same instance. Users outside {instance-name} won't be able to see the notice.</p>
|
||||
<p>a. Direct Messages → The notice will be visible only to its recipient in his DM inbox (there are no Direct Messages to more than one person).</p>
|
||||
<p>b. Set your account to "Make updates visible only to my followers" and "Ask me first if someone wants to follow me" in</p>
|
||||
<p class="indent">Settings → Profile → Subscription policy (below)</p>
|
||||
<p>c. Post to a private group of which you are a member → The post will only be visible to the group members (see above under <a href="#faq-16">Groups</a>). </p>
|
||||
<p>(Note to c: You can use any client to post to a private group by using the !group-tag.)</p>
|
||||
<p>d. Post to a public group and close the lock on the right of the drop-down menu beneath the message field. The post will then only be visible to the group members. (Although at the time of writing, this does not work. The post will be visible to everyone.)</p>
|
||||
<p><em>(Note to d: Make sure you don't leave "Everyone" or "My Colleagues at {instance-name}" selected, otherwise your post will go to the timelines of every {instance-name} user, which is not what you want if you close the lock)</em></p>
|
||||
<p><em>(Note to d: The lock method is only available in Classic {instance-name}. There is no lock feature in New {instance-name} or any other known client at the time of writing.)</em></p>
|
||||
|
||||
|
||||
<!-- 21 -->
|
||||
<h2 id="faq-21">Quale citar konversi o parti di li <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Sometimes in a blog-post or email, you don't want to cite just one notice but a whole conversation. Each notice, each reply, and each conversation has its own URL, and the ways to find them differ slightly in Classic {instance-name} and in New {instance-name}.</p>
|
||||
<p>New {instance-name}:</p>
|
||||
<p>In New {instance-name} click on the time stamp of a notice (or "details" if you have expanded it). This will show the notice page with the conversation expanded.</p>
|
||||
<p>Classic {instance-name}:</p>
|
||||
<p>Click on the the time stamp of any notice. The notice will reappear on a separate page. Click "in context". The whole conversation that this notice is involved in will be displayed on a new page, with the selected notice either on the top or further down.</p>
|
||||
|
||||
|
||||
<!-- 22 -->
|
||||
<h2 id="faq-22">Quale sequar klefovorti e hashtagi <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>Similar to following persons or groups you can subscribe to (or follow) hashtags and search words. Notices containing them will then appear in your Home timeline. </p>
|
||||
<p>Following search words and hashtags is not limited to notices from accounts on {instance-name} but covers notices from remote instances as well.</p>
|
||||
<p>To follow hashtags (# + ...) put the word with the hashtag-symbol # prefixed into the search box of <em>Classic {instance-name}</em> and press Enter. You'll arrive at the search result page. Similiar, to subscribe to search words, put them without hashtag-symbol into the search box. You'll get a much larger list because the search not only covers individual words but also looks for occurrences of the phrase inside larger phrases. To follow (or: subscribe to) both hashtags and search words, click on the tiny "Subscribe"-button in the upper right corner of the lists. You'll then receive the notices containing them in your Home Timeline.</p>
|
||||
<p>Following one word often yields too many results, so it is expedient to combine words and follow them as complete phrases.</p>
|
||||
<p>You can unfollow those notices by unfollowing the hashtags and search phrases.</p>
|
||||
<p>For an overview which phrases you follow, enter the URLs for<br>
|
||||
hashtags: <a href="{instance-url-with-protocol}{nickname}/tag-subscriptions">{instance-url-with-protocol}{nickname}/tag-subscriptions</a><br>
|
||||
search words and phrases: <a href="{instance-url-with-protocol}{nickname}/search-subscriptions">{instance-url-with-protocol}{nickname}/search-subscriptions</a></p>
|
||||
<p>On those pages you can manage your subscriptions, that is, add more phrases and hashtags or unfollow them.</p>
|
||||
|
||||
<!-- 23 -->
|
||||
<h2 id="faq-23">Pro quo mea repeto ne aparas ye altra exempleri? <a href="#faq-table-of-contents">Somito</a></h2>
|
||||
<p>In the latest versions of GNU social, repeats/requeets do not get sent to your followers on other instances. This was possible some time ago in StatusNet, but this feature has been removed due to a security issue. GNU social developers are working on a solution. In the meantime, if you really want your Repeat/Requeet to federate, you can always do a "manual repeat", i.e., write RQ @username, and then copy-paste the notice.</p>
|
||||
@@ -0,0 +1,16 @@
|
||||
<h3>Agi</h3>
|
||||
<p><span class="shortcut">n</span><span class="description">Nova mesajo</span></p>
|
||||
<p><span class="shortcut">f</span><span class="description">Markizar kom favorato</span></p>
|
||||
<p><span class="shortcut">r</span><span class="description">Respondar</span></p>
|
||||
<p><span class="shortcut">t</span><span class="description">Repetar</span></p>
|
||||
<p><span class="shortcut">Enter</span><span class="description">Estalar la mesajo</span></p>
|
||||
<p><span class="shortcut">Ctrl</span><span class="shortcut">Enter</span>o <span class="shortcut">Cmd ⌘</span><span class="shortcut">Enter</span><span class="description">Sendar la mesajo</span></p>
|
||||
<p><span class="shortcut">Esc</span><span class="description">Foldar omna estalita mesaji</span></p>
|
||||
|
||||
<h3>Navigo</h3>
|
||||
<p><span class="shortcut">?</span><span class="description">Ica menuo</span></p>
|
||||
<p><span class="shortcut">j</span><span class="description">Sequanta mesajo</span></p>
|
||||
<p><span class="shortcut">k</span><span class="description">Preiranta mesajo</span></p>
|
||||
|
||||
<h3>Disable</h3>
|
||||
<p>Keyboard shortcuts can be turned off on <a href="{instance-url-with-protocol}settings/qvitter">the Qvitter settings page</a>.</p>
|
||||
@@ -0,0 +1,15 @@
|
||||
<p>{instance-name} ne esas servado e vu ne esas kliento hike. Ni esas mikra parto di plu granda chanjo, kreanta granda descentraligita komunitato. Ico signifikas ke ni ne devas esar neutra pri la kontenajo ye nia exemplero di GNU Social. Se vu ne prizas la direciono segun quan ica exemplero esas iranta, vu povas libere livar vers altra exemplero od iniciar la vua. Vu povos ankore sequar ed esar sequata (e blokusata) da uzeri ye ca exemplero.</p>
|
||||
|
||||
<p>Kontree a la dominaco administrala di la komercala sociala moyeni, ico kreas ulaspeca egala povo-strukturo. Ni esas kapabligita pri protektar l'una e l'altra ek persekuto ed opreso, ma sen censuro.</p>
|
||||
|
||||
<p>Ye ca exemplero, uzeri qui persekutas altri esos ekpulsita. Ni anke forte opozas rasismo, sexuismo, kapablismo, homeosexual-fobio e transsexual-fobio. Tala expresi nesekurigas la ret-situo por altra uzeri, e praktikale restriktas lia libereso di expreso.</p>
|
||||
|
||||
<p>La publika tempolineo esas konsiderita specale sentema loko. Olu esas quon nova uzeri unesme vidas, ed omna registragita uzeri vidos la mesaji publikigita ibe. Moderanti darfas exkluzar uzeri ek aparar en la publika tempolineo irgatempe, sen avizo, permanante o provizore. Konsiderez kom privilejo esar publikigita en la publika tempolineo, ne yuro. Se vu esas exkluzita ek publika tempolineo, vu povas durar omna altra praktiko ye la ret-situo tote quale irga altra uzero.</p>
|
||||
|
||||
<p>Anunco e komercala enti ne esas permisita ye ca exemplero. Ni esas tote neprofita e nia spensi esas tote pagita da individui. <a href="mailto:{instance-email}">Ni povas helpar vu</a> iniciar vua propra exemplero di GNU Social se vua intenco esas komercala.</p>
|
||||
|
||||
<p>Omna kontenajo ye ca ret-situo esas licencita per <a href="{instance-license-url}">{instance-license-title}</a>.</p>
|
||||
|
||||
<p>Each user is responsible for the content they submit. If you have any questions
|
||||
about something posted on this instance, contact the user in question first. As a last resort you
|
||||
can email the <a href="mailto:{instance-email}">admins</a>.</p>
|
||||
@@ -42,8 +42,8 @@
|
||||
<p>GNU social/StatusNet er software som muliggjør en desentralisert mikroblogging plattform.</p>
|
||||
<p>Brukere av en instans (eller: tjeneste) kan følge, bli fulgt av og kommunisere med brukere fra andre instanser.</p>
|
||||
<p>Eksempler på andre instanser er , <a href="https://loadaverage.org/">loadaverage.org</a>, <a href="http://status.vinilox.eu/">status.vinilox.eu</a>, <a href="http://micro.fragdev.com/">micro.fragdev.com</a>, <a href="https://gnusocial.de/">gnusocial.de</a>, <a href="https://indy.im/">indy.im</a>, <a href="https://quitter.no/">quitter.no, <a href="http://rainbowdash.net/">rainbowdash.net</a>, osv. Nåværende antall av slike instanser som benytter GNU social/StatusNet software er trolig ca. 50, {instance-name} er en av disse. Disse instansene kan kommunisere med hverandre, selv om de kjører på ulike maskiner. Det er programvaren som benyttes (GNU social/StatusNet) og protokollen (OStatus) som muliggjør dette. På samme måte som forskjellige e-post tjenere kan kommunisere med hverandre, kan også de ulike instanser av GNU social/StatusNet kommunisere med hverandre.</p>
|
||||
<p>Kobling mellom instansene blir etablert idet ulike brukere starter å følge hverandre. Ved å starte å følge andre brukere, blir nettverket knyttet sammen til en kombinert struktur. Dette oppleves som ett nettverk, selv om det i realiteten er en struktur av uavhengige instanser. Dette benevnes som "the Federation" - eller føderasjonen. Det betyr at instansene federerer/utveksler informasjon mellom hverandre. GNU social/StatusNet er strukturert på en slik måte at idet en bruker følger bruker <strong>a</strong> fra instans <strong>A</strong> til en bruker <strong>b</strong> fra instans til <strong>B</strong> for å gjøre <strong>b</strong> synlig for alle i instans <strong>A</strong> via <em>Hele Nettverket</em>. (See nedenfor <a href="#faq-9">De tre tidslinjene</a>.) Hele nettverket er bredden av nettverk til instansen -sett fra instans {instance-name}. Denne tidslinjen ser forskjellig ut på de ulike instanser, dette fordi instansene har ulike følgere til distanserte instanser enn på denne instansen - {instance-name}. </p>
|
||||
<p>Det eksisterer ingen sentral "instans/server/tjeneste" som ved f.eks utlgjengelighet av tjenesten kunne ha ført til at nettverket ikke var tilgjengelig. Hvis en instans ikke er tilgjengelig eller at administrator begynner å utvikle instansen i en retning du ikke liker, så kan du som bruker opprette en konto på en av de andre instansene. Du vil alikevel være på GNU social-network og fortsatt ha muligheten til å kommunisere med dine GNU social-venner. Du trenger kun å fortelle dine kontakter adressen til din nye instans.</p>
|
||||
<p>Kobling mellom instansene blir etablert idet ulike brukere starter å følge hverandre. Ved å starte å følge andre brukere, blir nettverket knyttet sammen til en kombinert struktur. Dette oppleves som ett nettverk, selv om det i realiteten er en struktur av uavhengige instanser. Dette benevnes som "the Federation" - eller føderasjonen. Det betyr at instansene utveksler informasjon seg i mellom. GNU social/StatusNet er strukturert på en slik måte at idet en bruker følger bruker <strong>a</strong> fra instans <strong>A</strong> til en bruker <strong>b</strong> fra instans til <strong>B</strong> for å gjøre <strong>b</strong> synlig for alle i instans <strong>A</strong> via <em>Hele Nettverket</em>. (Se nedenfor <a href="#faq-9">De tre tidslinjene</a>.) Hele nettverket er bredden av nettverk til instansen -sett fra instans {instance-name}. Denne tidslinjen ser forskjellig ut på de ulike instanser, dette fordi instansene har ulike følgere til distanserte instanser enn på denne instansen - {instance-name}. </p>
|
||||
<p>Det eksisterer ingen sentral "instans/server/tjeneste" som ved f.eks utilgjengelighet av tjenesten kunne ha ført til at nettverket ikke var tilgjengelig. Hvis en instans ikke er tilgjengelig eller at administrator begynner å utvikle instansen i en retning du ikke liker, så kan du som bruker opprette en konto på en av de andre instansene. Du vil allikevel være på GNU social-network og fortsatt ha muligheten til å kommunisere med dine GNU social-venner. Du trenger kun å fortelle dine kontakter adressen til din nye instans.</p>
|
||||
<p>Adresser på GNU social ser slik ut:</p>
|
||||
<p class="indent">@user@instance.org</p>
|
||||
<p>Din adresse er:</p>
|
||||
@@ -0,0 +1,16 @@
|
||||
<h3>Aksjoner</h3>
|
||||
<p><span class="shortcut">n</span><span class="description">Ny melding</span></p>
|
||||
<p><span class="shortcut">f</span><span class="description">Favorittmarkere</span></p>
|
||||
<p><span class="shortcut">r</span><span class="description">Svare</span></p>
|
||||
<p><span class="shortcut">t</span><span class="description">Requeete meldingen</span></p>
|
||||
<p><span class="shortcut">Linjeskift</span><span class="description">Åpne og lukke</span></p>
|
||||
<p><span class="shortcut">Ctrl</span><span class="shortcut">Linjeskift</span>eller <span class="shortcut">Cmd ⌘</span><span class="shortcut">Linjeskift</span><span class="description">Sende en melding</span></p>
|
||||
<p><span class="shortcut">Esc</span><span class="description">Lukk alt og åpne qvitter</span></p>
|
||||
|
||||
<h3>Navigere</h3>
|
||||
<p><span class="shortcut">?</span><span class="description">Denne menyen</span></p>
|
||||
<p><span class="shortcut">j</span><span class="description">Neste melding</span></p>
|
||||
<p><span class="shortcut">k</span><span class="description">Forrige melding</span></p>
|
||||
|
||||
<h3>Disable</h3>
|
||||
<p>Keyboard shortcuts can be turned off on <a href="{instance-url-with-protocol}settings/qvitter">the Qvitter settings page</a>.</p>
|
||||
@@ -0,0 +1,33 @@
|
||||
<p>{instance-name} er ikke en tjeneste og du er ingen kunde her. Vi er en liten del av en
|
||||
større sosial bevegelse for å skape et desentralisert nettverk. Det betyr at
|
||||
vi ikke må være nøytrale til innholdet på vår GNU social instans for å opprettholde
|
||||
ytringsfrihet på nettverket. Om du ikke liker innretningen på vår instans kan du flytte
|
||||
til en annen eller starte din egen. Du vil fortsatt ha muligheten til å følge og bli fulgt av
|
||||
(og blokkert av) brukere på denne instansen.</p>
|
||||
|
||||
<p>Til forskjell fra de kommersielle sosiale mediene,
|
||||
skaper ett desentralisert nettverk en flatere struktur. Vårt formål er å beskytte hverandre
|
||||
ifra trakassering og forakt, men uten å innføre en sentral sensur.</p>
|
||||
|
||||
<p>På denne instansen vil brukere som trakasserer andre bli fjernet. Vi forsøker
|
||||
også å være årvåkne mot f.eks rasisme, sexisme, funko-, trans- og homofobi. Et slikt ytrende
|
||||
skaper et usikkert rom for andre brukere, og i praksis begrenser det deres ytringsfrihet.</p>
|
||||
|
||||
|
||||
<p>Den offentlige tidslinjen, under rubrikken "Hele instansen strøm", anser vi som særskilt
|
||||
følsomt. Dette er vårt ansikt utad, og alle får se hva som skrives der - det er ikke bare
|
||||
brukernes følgere. Moderator kan derfor skjule brukere fra den offentlige tidslinjen,
|
||||
uten noen forvarsel. Det er ingen rettighet å være synlig i den offentlige tidslinjen. Om du er skjult
|
||||
fra den offentlige tidslinjen kan du fortsatt bruke instansens alle funksjoner slik som
|
||||
alla andre brukere.</p>
|
||||
|
||||
<p>Reklame og kommersielle brukere er ikke tillat på denne instansen. Vi drifter denne instansen
|
||||
fullstendig ikke-kommersiell og alle våre kostnader betales av donasjoner fra brukerne.
|
||||
<a href="mailto:{instance-email}">Vi kan hjelpe deg</a> å starte opp din egen GNU social-
|
||||
instans om du har kommersielle intensjoner.</p>
|
||||
|
||||
<p>Alt innhold på instansen publiseres under lisensen <a href="{instance-license-url}">{instance-license-title}</a>.</p>
|
||||
|
||||
<p>Each user is responsible for the content they submit. If you have any questions
|
||||
about something posted on this instance, contact the user in question first. As a last resort you
|
||||
can email the <a href="mailto:{instance-email}">admins</a>.</p>
|
||||
@@ -1,28 +0,0 @@
|
||||
<p>{instance-name} er ikke å betrakte som en tjeneste og du er ikke vår kunde. Vi er en liten del av
|
||||
en større sosial bevegelse, som utvikler et digitalt desentralisert felleskap. Med dette mener vi
|
||||
at vi har ingen forpliktelse i å være nøytrale til innholdet på våre instanser. Hvis du ikke liker
|
||||
retningen vår instansen beveger seg i eller vår holdning til innhold, står du fritt til å flytte deg over
|
||||
til en annen instans eller starte din egen.
|
||||
Du vil alikevel ha muligheten til å følge andre eller bli fulgt av andre (også blokkert) av brukere på denne instansen.</p>
|
||||
|
||||
<p>I kontrast til et kommersielt sosialt medium, så skaper desentraliserte nettverk en flatere makt struktur.
|
||||
Det er ingen ovenfra-ned autoriteter. Med en slik desentralisert struktur gjør vi det mulig å beskytte hverandre
|
||||
fra trakassering og undertrykkelse, men uten sensur.</p>
|
||||
|
||||
<p>Brukere av denne instansen som uttrykker trakassering vil bli utestengt dvs. slettet. Vi har også en sterk holdning
|
||||
mot de som måtte uttrykke rasisme, sexisme, ableism, homo- og transphobia. Vi tror uttrykksformer som retter seg mot dette
|
||||
gjør vår instans usikker for andre brukere, og i praksis begrenser deres rettighet til å uttrykke seg fritt.
|
||||
Det er forskjell på å respektere og akseptere.</p>
|
||||
|
||||
<p>Strømmen som viser vår offentlige tidslinje er å betrakte som en sensitiv plass. Det er denne tidslinjen nye brukere ser først,
|
||||
samt at alle registrerte brukere vil se innlegg publisert på tidslinjen. Moderatorer kan eksludere brukere
|
||||
når som helst fra å synes i den offentlige tidslinjen, dette uten noen form for permanent eller temporær advarsel.
|
||||
Det faktum at du kan publisere på den offentlige tidslinjen, ber vi deg betrakte som et privilegium og ikke som en rettighet.
|
||||
Hvis du blir ekskludert fra den offentlige tidslinjen, kan du alikvel benytte funksjonaliteten på instansen som alle andre brukere.</p>
|
||||
|
||||
<p>Reklame og alle andre kommersielle uttrykksformer er ikke tillatt på denne instansen. Vi er en
|
||||
ikke-profitt instans og kostnader for å drive instansen er betalt av donasjoner fra individer.
|
||||
<a href="mailto:{instance-email}">Vi kan hjelpe deg</a> å starte din egen GNU social instans
|
||||
hvis din intensjon er kommersiell virksomhet.</p>
|
||||
|
||||
<p>Alt innhold på denne nettsiden er lisensiert med <a href="{instance-license-url}">{instance-license-title}</a>.</p>
|
||||
@@ -0,0 +1,16 @@
|
||||
<h3>Handlingar</h3>
|
||||
<p><span class="shortcut">n</span><span class="description">Nytt qvitter</span></p>
|
||||
<p><span class="shortcut">f</span><span class="description">Favoritmarkera</span></p>
|
||||
<p><span class="shortcut">r</span><span class="description">Svara</span></p>
|
||||
<p><span class="shortcut">t</span><span class="description">Requeeta</span></p>
|
||||
<p><span class="shortcut">Enter</span><span class="description">Öppna och stäng</span></p>
|
||||
<p><span class="shortcut">Ctrl</span><span class="shortcut">Enter</span>eller <span class="shortcut">Cmd ⌘</span><span class="shortcut">Enter</span><span class="description">Skicka qvitter</span></p>
|
||||
<p><span class="shortcut">Esc</span><span class="description">Stäng allt öppnat qvitter</span></p>
|
||||
|
||||
<h3>Navigation</h3>
|
||||
<p><span class="shortcut">?</span><span class="description">Denna meny</span></p>
|
||||
<p><span class="shortcut">j</span><span class="description">Nästa qvitter</span></p>
|
||||
<p><span class="shortcut">k</span><span class="description">Föregående qvitter</span></p>
|
||||
|
||||
<h3>Stäng av</h3>
|
||||
<p>Kortkommandon kan avaktiveras på <a href="{instance-url-with-protocol}settings/qvitter">Qvitters inställningssida</a>.</p>
|
||||
@@ -1,8 +1,8 @@
|
||||
<p>{instance-name} är inte en tjänst och du är ingen kund här. Vi är en liten del av en
|
||||
större social rörelse för att skapa ett stort decentraliserad nätverk. Det betyder att
|
||||
större social rörelse för att skapa ett stort decentraliserad nätverk. Det betyder att
|
||||
vi inte måste vara neutrala till innehållet på vår GNU social-instans för att upprätthålla
|
||||
yttrandefrihet på nätverket. Om du inte gillar inriktningen på vår instans kan du flytta
|
||||
till en annan eller starta en egen. Du kommer fortfarande kunna följa och bli följd av
|
||||
till en annan eller starta en egen. Du kommer fortfarande kunna följa och bli följd av
|
||||
(och blockad av) användare på den här instansen.</p>
|
||||
|
||||
<p>Till skillnad från den de toppstyrda kommersiella sociala medierna,
|
||||
@@ -13,9 +13,8 @@ från trakasserier och förtryck, men utan att införa en central censur.</p>
|
||||
också vara vaksamma mot t ex rasism, sexism, funko-, trans- och homofobi. Sådana yttranden
|
||||
skapar ett osäkert rum för andra användare, och i praktiken begränsar det deras yttrandefrihet.</p>
|
||||
|
||||
|
||||
<p>Den offentliga tidslinjen, under rubriken "Hela sajtens flöde", anser vi vara särskilt
|
||||
känslig. Dels är den vårt ansikte utåt, dels får alla se vad som skrivs där – inte bara
|
||||
känslig. Dels är den vårt ansikte utåt, dels får alla se vad som skrivs där – inte bara
|
||||
användarens följare. Moderatorer kan därför dölja användare från den offentliga tidslinjen,
|
||||
närsomhelst och utan förvarning. Det är ingen rättighet att synas där. Om du dolts från
|
||||
den offentliga tidslinjen kan du fortfarande använda sajtens alla funktioner precis som
|
||||
@@ -27,3 +26,7 @@ helt icke-kommersiellt och alla våra omkostnader betalas av donationer från en
|
||||
instans om du har kommersiella intentioner.</p>
|
||||
|
||||
<p>Allt innehåll på sajten publiceras under licensen <a href="{instance-license-url}">{instance-license-title}</a>.</p>
|
||||
|
||||
<p>Varje användare ansvarar för innehållet som de lägger upp. Om du har några betänkligheter
|
||||
om något som postats på denna instans, hör av dig till användaren i fråga först. Om det
|
||||
inte hjälper kan du mejla sajtens <a href="mailto:{instance-email}">administratörer</a>.</p>
|
||||
|
||||
@@ -1,394 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Base class for API actions that require authentication
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @author Brenda Wallace <shiny@cpan.org>
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author mEDI <medi@milaro.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page authentication Authentication
|
||||
|
||||
StatusNet supports HTTP Basic Authentication and OAuth for API calls.
|
||||
|
||||
@warning Currently, users who have created accounts without setting a
|
||||
password via OpenID, Facebook Connect, etc., cannot use the API until
|
||||
they set a password with their account settings panel.
|
||||
|
||||
@section HTTP Basic Auth
|
||||
|
||||
|
||||
|
||||
@section OAuth
|
||||
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Actions extending this class will require auth
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAuthAction extends ApiAction
|
||||
{
|
||||
var $auth_user_nickname = null;
|
||||
var $auth_user_password = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running, looks for an OAuth request,
|
||||
* and outputs basic auth header if needed
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// NOTE: $this->auth_user has to get set in prepare(), not handle(),
|
||||
// because subclasses do stuff with it in their prepares.
|
||||
|
||||
|
||||
// qvitterfix, accepts regular login session
|
||||
if (common_logged_in()) {
|
||||
$this->scoped = Profile::current();
|
||||
$this->auth_user = $this->scoped->getUser();
|
||||
if (!$this->auth_user->hasRight(Right::API)) {
|
||||
// TRANS: Authorization exception thrown when a user without API access tries to access the API.
|
||||
throw new AuthorizationException(_('Not allowed to use API.'));
|
||||
}
|
||||
$this->access = self::READ_WRITE;
|
||||
Event::handle('EndSetApiUser', array($this->auth_user));
|
||||
} else {
|
||||
$oauthReq = $this->getOAuthRequest();
|
||||
|
||||
if (!$oauthReq) {
|
||||
if ($this->requiresAuth()) {
|
||||
$this->checkBasicAuthUser(true);
|
||||
} else {
|
||||
// Check to see if a basic auth user is there even
|
||||
// if one's not required
|
||||
$this->checkBasicAuthUser(false);
|
||||
}
|
||||
} else {
|
||||
$this->checkOAuthRequest($oauthReq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE: Make sure we're scoped properly based on the auths!
|
||||
if (isset($this->auth_user) && !empty($this->auth_user)) {
|
||||
$this->scoped = $this->auth_user->getProfile();
|
||||
} else {
|
||||
$this->scoped = null;
|
||||
}
|
||||
|
||||
// legacy user transferral
|
||||
// TODO: remove when sure no extended classes need it
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
// Reject API calls with the wrong access level
|
||||
|
||||
if ($this->isReadOnly($args) == false) {
|
||||
if ($this->access != self::READ_WRITE) {
|
||||
// TRANS: Client error 401.
|
||||
$msg = _('API resource requires read-write access, ' .
|
||||
'but you only have read access.');
|
||||
$this->clientError($msg, 401);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the request is an OAuth request.
|
||||
* This is to avoid doign any unnecessary DB lookups.
|
||||
*
|
||||
* @return mixed the OAuthRequest or false
|
||||
*/
|
||||
function getOAuthRequest()
|
||||
{
|
||||
ApiOAuthAction::cleanRequest();
|
||||
|
||||
$req = OAuthRequest::from_request();
|
||||
|
||||
$consumer = $req->get_parameter('oauth_consumer_key');
|
||||
$accessToken = $req->get_parameter('oauth_token');
|
||||
|
||||
// XXX: Is it good enough to assume it's not meant to be an
|
||||
// OAuth request if there is no consumer or token? --Z
|
||||
|
||||
if (empty($consumer) || empty($accessToken)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $req;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the OAuth request signature, sets the auth user
|
||||
* and access type (read-only or read-write)
|
||||
*
|
||||
* @param OAuthRequest $request the OAuth Request
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function checkOAuthRequest($request)
|
||||
{
|
||||
$datastore = new ApiGNUsocialOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
try {
|
||||
$server->verify_request($request);
|
||||
|
||||
$consumer = $request->get_parameter('oauth_consumer_key');
|
||||
$access_token = $request->get_parameter('oauth_token');
|
||||
|
||||
$app = Oauth_application::getByConsumerKey($consumer);
|
||||
|
||||
if (empty($app)) {
|
||||
common_log(
|
||||
LOG_WARNING,
|
||||
'API OAuth - Couldn\'t find the OAuth app for consumer key: ' .
|
||||
$consumer
|
||||
);
|
||||
// TRANS: OAuth exception thrown when no application is found for a given consumer key.
|
||||
throw new OAuthException(_('No application for that consumer key.'));
|
||||
}
|
||||
|
||||
// set the source attr
|
||||
if ($app->name != 'anonymous') {
|
||||
$this->source = $app->name;
|
||||
}
|
||||
|
||||
|
||||
$appUser = Oauth_application_user::getKV('token', $access_token);
|
||||
|
||||
if (!empty($appUser)) {
|
||||
// If access_type == 0 we have either a request token
|
||||
// or a bad / revoked access token
|
||||
|
||||
if ($appUser->access_type != 0) {
|
||||
// Set the access level for the api call
|
||||
$this->access = ($appUser->access_type & Oauth_application::$writeAccess)
|
||||
? self::READ_WRITE : self::READ_ONLY;
|
||||
|
||||
// Set the auth user
|
||||
if (Event::handle('StartSetApiUser', array(&$user))) {
|
||||
$user = User::getKV('id', $appUser->profile_id);
|
||||
if (!empty($user)) {
|
||||
if (!$user->hasRight(Right::API)) {
|
||||
// TRANS: Authorization exception thrown when a user without API access tries to access the API.
|
||||
throw new AuthorizationException(_('Not allowed to use API.'));
|
||||
}
|
||||
}
|
||||
$this->auth_user = $user;
|
||||
// FIXME: setting the value returned by common_current_user()
|
||||
// There should probably be a better method for this. common_set_user()
|
||||
// does lots of session stuff.
|
||||
global $_cur;
|
||||
$_cur = $this->auth_user;
|
||||
Event::handle('EndSetApiUser', array($user));
|
||||
}
|
||||
|
||||
$msg = "API OAuth authentication for user '%s' (id: %d) on behalf of " .
|
||||
"application '%s' (id: %d) with %s access.";
|
||||
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
$msg,
|
||||
$this->auth_user->nickname,
|
||||
$this->auth_user->id,
|
||||
$app->name,
|
||||
$app->id,
|
||||
($this->access = self::READ_WRITE) ? 'read-write' : 'read-only'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// TRANS: OAuth exception given when an incorrect access token was given for a user.
|
||||
throw new OAuthException(_('Bad access token.'));
|
||||
}
|
||||
} else {
|
||||
// Also should not happen.
|
||||
// TRANS: OAuth exception given when no user was found for a given token (no token was found).
|
||||
throw new OAuthException(_('No user for that token.'));
|
||||
}
|
||||
|
||||
} catch (OAuthException $e) {
|
||||
$this->logAuthFailure($e->getMessage());
|
||||
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
|
||||
$this->clientError($e->getMessage(), 401);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this API resource require authentication?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
public function requiresAuth()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a user specified via HTTP basic auth. If there isn't
|
||||
* one, try to get one by outputting the basic auth header.
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function checkBasicAuthUser($required = true)
|
||||
{
|
||||
$this->basicAuthProcessHeader();
|
||||
|
||||
$realm = common_config('api', 'realm');
|
||||
|
||||
if (empty($realm)) {
|
||||
$realm = common_config('site', 'name') . ' API';
|
||||
}
|
||||
|
||||
if (empty($this->auth_user_nickname) && $required) {
|
||||
header('WWW-Authenticate: Basic realm="' . $realm . '"');
|
||||
|
||||
// show error if the user clicks 'cancel'
|
||||
// TRANS: Client error thrown when authentication fails becaus a user clicked "Cancel".
|
||||
$this->clientError(_('Could not authenticate you.'), 401);
|
||||
|
||||
} elseif($required) {
|
||||
|
||||
$user = common_check_user($this->auth_user_nickname,
|
||||
$this->auth_user_password);
|
||||
|
||||
if (Event::handle('StartSetApiUser', array(&$user))) {
|
||||
|
||||
if (!empty($user)) {
|
||||
if (!$user->hasRight(Right::API)) {
|
||||
// TRANS: Authorization exception thrown when a user without API access tries to access the API.
|
||||
throw new AuthorizationException(_('Not allowed to use API.'));
|
||||
}
|
||||
$this->auth_user = $user;
|
||||
}
|
||||
|
||||
Event::handle('EndSetApiUser', array($user));
|
||||
}
|
||||
|
||||
$this->access = self::READ_WRITE;
|
||||
|
||||
if (empty($this->auth_user) && ($required || isset($_SERVER['PHP_AUTH_USER']))) {
|
||||
$msg = sprintf(
|
||||
"basic auth nickname = %s",
|
||||
$this->auth_user_nickname
|
||||
);
|
||||
$this->logAuthFailure($msg);
|
||||
// TRANS: Client error thrown when authentication fails.
|
||||
$this->clientError(_('Could not authenticate you.'), 401);
|
||||
}
|
||||
} else {
|
||||
|
||||
// all get rw access for actions that don't need auth
|
||||
$this->access = self::READ_WRITE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the HTTP headers and set the auth user. Decodes HTTP_AUTHORIZATION
|
||||
* param to support basic auth when PHP is running in CGI mode.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function basicAuthProcessHeader()
|
||||
{
|
||||
$authHeaders = array('AUTHORIZATION',
|
||||
'HTTP_AUTHORIZATION',
|
||||
'REDIRECT_HTTP_AUTHORIZATION'); // rewrite for CGI
|
||||
$authorization_header = null;
|
||||
foreach ($authHeaders as $header) {
|
||||
if (isset($_SERVER[$header])) {
|
||||
$authorization_header = $_SERVER[$header];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$this->auth_user_nickname = $_SERVER['PHP_AUTH_USER'];
|
||||
$this->auth_user_password = $_SERVER['PHP_AUTH_PW'];
|
||||
} elseif (isset($authorization_header)
|
||||
&& strstr(substr($authorization_header, 0, 5), 'Basic')) {
|
||||
|
||||
// Decode the HTTP_AUTHORIZATION header on php-cgi server self
|
||||
// on fcgid server the header name is AUTHORIZATION
|
||||
$auth_hash = base64_decode(substr($authorization_header, 6));
|
||||
list($this->auth_user_nickname,
|
||||
$this->auth_user_password) = explode(':', $auth_hash);
|
||||
|
||||
// Set all to null on a empty basic auth request
|
||||
|
||||
if (empty($this->auth_user_nickname)) {
|
||||
$this->auth_user_nickname = null;
|
||||
$this->auth_password = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an API authentication failure. Collect the proxy and IP
|
||||
* and log them
|
||||
*
|
||||
* @param string $logMsg additional log message
|
||||
*/
|
||||
function logAuthFailure($logMsg)
|
||||
{
|
||||
list($proxy, $ip) = common_client_ip();
|
||||
|
||||
$msg = sprintf(
|
||||
'API auth failure (proxy = %1$s, ip = %2$s) - ',
|
||||
$proxy,
|
||||
$ip
|
||||
);
|
||||
|
||||
common_log(LOG_WARNING, $msg . $logMsg);
|
||||
}
|
||||
}
|
||||
|
Antes Largura: | Altura: | Tamanho: 1.5 KiB |
|
Antes Largura: | Altura: | Tamanho: 8.9 KiB |
|
Antes Largura: | Altura: | Tamanho: 3.8 KiB |
|
Antes Largura: | Altura: | Tamanho: 5.3 KiB |
|
Antes Largura: | Altura: | Tamanho: 3.2 KiB |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="50" height="50" viewBox="-2 0 50 50" enable-background="new -2.001 -0.001 50.003 50.003" xml:space="preserve"><g transform="translate(-156.94799,-309.83779)"><g transform="translate(106.33914,-525.03507)"><path fill="#A22430" d="M89.8 834.9H57.4c-3.6 0-6.6 2.9-6.6 6.6v26.3c0 3.6 2.9 6.6 6.6 6.6h19.5c0 7.4-10.1 10.6-10.1 10.6s17-0.1 19.4-10.6h3.6c3.6 0 6.6-2.9 6.6-6.6v-26.3C96.4 837.8 93.5 834.9 89.8 834.9zM73.8 869.1c-8.7-0.4-10.7-7.3-10.8-12 0-2.5 0.4-5.4 2.5-7.4 -2.2-1.2-2.1-3.6-2.1-5 0-2.1 3.1-5.1 3.8-4.4 0.7 0.6-1.2 1.2-1 4.3 0.1 1.3-0.3 2.4 2.2 2.4 1.7 0 1-1.5 3.2-1.5 1.3 0 1.8 0.8 1.9 1.5 0.2-0.7 0.7-1.5 1.9-1.5 2.2 0 1.5 1.5 3.2 1.5 2.6 0 2.2-1 2.2-2.4 0.1-3.1-1.7-3.7-1-4.3 0.7-0.6 3.7 3 3.8 4.4 0.1 1.5 0.1 3.8-2.1 5 2.5 2.4 2.8 5.6 2.8 5.6l-4.3-0.1c0 0-1-4.4-6.1-4.2 -5.2 0.2-5.8 1.1-5.8 6.6 0 5.5 2.4 7.3 6.1 7.5 5.8 0.2 5.2-3 5.2-3l-2.7 0.2 -1.5-4h9.2C84.4 862.7 82.6 869.5 73.8 869.1z"/></g></g></svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 1.0 KiB |
|
Depois Largura: | Altura: | Tamanho: 3.2 KiB |
|
Depois Largura: | Altura: | Tamanho: 4.0 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.3 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.5 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.0 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.4 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.2 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.3 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.6 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 3.1 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.4 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.4 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.6 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.6 KiB |
|
Depois Largura: | Altura: | Tamanho: 6.4 KiB |
|
Depois Largura: | Altura: | Tamanho: 3.1 KiB |
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="mstile-70x70.png"/>
|
||||
<square150x150logo src="mstile-150x150.png"/>
|
||||
<square310x310logo src="mstile-310x310.png"/>
|
||||
<wide310x150logo src="mstile-310x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
Depois Largura: | Altura: | Tamanho: 879 B |
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.4 KiB |
|
Depois Largura: | Altura: | Tamanho: 15 KiB |
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "GNU social",
|
||||
"icons": [
|
||||
{
|
||||
"src": "android-chrome-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image\/png",
|
||||
"density": 0.75
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image\/png",
|
||||
"density": 1
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image\/png",
|
||||
"density": 1.5
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image\/png",
|
||||
"density": 2
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image\/png",
|
||||
"density": 3
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image\/png",
|
||||
"density": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Depois Largura: | Altura: | Tamanho: 3.1 KiB |
|
Depois Largura: | Altura: | Tamanho: 3.1 KiB |
|
Depois Largura: | Altura: | Tamanho: 3.4 KiB |
|
Depois Largura: | Altura: | Tamanho: 5.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.4 KiB |
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M1129 6996 c-2 -2 -25 -7 -51 -10 -91 -12 -306 -92 -316 -118 -2 -4
|
||||
-9 -8 -15 -8 -15 0 -130 -92 -181 -145 -124 -129 -215 -311 -244 -489 -9 -56
|
||||
-9 -3920 0 -3974 66 -386 362 -686 748 -757 61 -11 335 -14 1479 -15 772 0
|
||||
1407 -2 1411 -5 12 -7 -3 -155 -25 -251 -48 -208 -171 -417 -355 -604 -110
|
||||
-111 -139 -137 -241 -212 -187 -139 -389 -249 -644 -354 l-130 -54 95 5 c52 3
|
||||
115 7 140 10 25 3 77 7 115 10 39 3 81 7 95 9 14 3 52 7 85 11 32 4 62 8 65
|
||||
10 3 1 28 6 55 9 28 4 97 16 155 27 58 11 116 23 130 25 63 12 307 79 420 116
|
||||
728 237 1195 658 1340 1206 l11 42 267 1 c147 0 291 2 319 4 136 11 292 67
|
||||
417 149 214 141 350 346 400 606 22 113 22 3887 0 4000 -41 212 -137 384 -294
|
||||
526 -95 86 -261 177 -365 200 -149 34 -111 33 -2521 34 -1298 0 -2363 -2
|
||||
-2365 -4z m1481 -755 c17 -33 12 -52 -38 -141 -93 -166 -114 -256 -111 -475 2
|
||||
-149 3 -163 27 -207 27 -51 56 -70 137 -88 65 -15 202 -15 240 -1 17 7 62 46
|
||||
102 87 39 41 88 81 108 90 87 36 232 26 302 -21 43 -29 90 -89 98 -126 6 -29
|
||||
25 -41 25 -16 0 21 41 90 68 116 14 13 49 34 76 47 43 20 64 23 136 20 49 -1
|
||||
101 -10 122 -19 21 -9 71 -50 111 -91 40 -41 86 -80 103 -87 46 -18 195 -13
|
||||
272 11 54 16 71 26 90 54 34 50 39 85 40 253 0 199 -13 257 -94 419 -71 142
|
||||
-76 173 -33 188 20 7 37 4 70 -12 51 -25 182 -150 243 -232 22 -30 44 -57 47
|
||||
-60 15 -12 92 -143 121 -206 32 -67 33 -73 33 -204 0 -152 -6 -210 -30 -290
|
||||
-36 -118 -100 -212 -189 -277 -34 -25 -63 -46 -65 -48 -2 -2 23 -35 56 -72
|
||||
110 -125 201 -283 261 -453 35 -99 66 -234 59 -253 -4 -11 -31 -13 -114 -11
|
||||
-59 1 -190 3 -290 5 l-182 2 -16 47 c-21 65 -69 154 -120 225 -38 53 -73 88
|
||||
-165 166 -50 42 -204 108 -300 128 -123 26 -387 22 -577 -8 -112 -18 -125 -21
|
||||
-193 -48 -102 -40 -165 -93 -214 -179 -26 -46 -62 -173 -70 -249 -3 -27 -8
|
||||
-74 -11 -102 -8 -66 -8 -453 -1 -513 5 -41 10 -74 22 -155 17 -107 75 -264
|
||||
130 -350 118 -185 296 -291 557 -329 83 -12 347 -13 402 -2 17 3 46 9 65 12
|
||||
70 11 186 56 239 92 101 70 150 153 155 267 l1 30 -70 -1 c-38 0 -123 -3 -188
|
||||
-5 l-119 -4 -69 185 c-38 102 -83 223 -100 270 -18 47 -34 90 -36 96 -5 14
|
||||
1269 15 1279 0 3 -5 5 -28 3 -50 -3 -23 -7 -83 -10 -135 -3 -51 -7 -96 -9
|
||||
-100 -2 -3 -7 -31 -11 -61 -9 -73 -57 -259 -89 -343 -150 -395 -440 -667 -819
|
||||
-766 -67 -18 -151 -33 -257 -46 -52 -6 -323 -7 -360 -1 -14 2 -53 7 -88 10
|
||||
-128 13 -284 51 -415 102 -275 106 -497 287 -659 540 -79 123 -183 377 -213
|
||||
524 -7 30 -23 114 -30 155 -2 17 -7 40 -9 51 -23 116 -24 568 -1 636 2 7 6 29
|
||||
9 48 31 212 125 424 259 582 l55 64 -42 27 c-50 31 -123 106 -158 163 -30 46
|
||||
-72 175 -83 249 -4 28 -8 109 -10 182 -2 155 15 227 84 343 47 79 142 200 192
|
||||
245 49 43 132 103 160 114 42 17 87 13 99 -8z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 3.0 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 3.9 KiB |