You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
7.6 KiB

9 years ago
9 years ago
9 years ago
  1. <?php
  2. use Symfony\Component\HttpFoundation\Request;
  3. use Symfony\Component\HttpFoundation\Response;
  4. class Controller {
  5. public $http;
  6. public function __construct() {
  7. $this->http = new Telegraph\HTTP();
  8. }
  9. private function _is_logged_in(Request $request, Response $response) {
  10. session_start();
  11. if(!session('user_id')) {
  12. session_destroy();
  13. $response->setStatusCode(302);
  14. $response->headers->set('Location', '/login?return_to='.$request->getRequestURI());
  15. return false;
  16. } else {
  17. return true;
  18. }
  19. }
  20. private function _get_role(Request $request, Response $response) {
  21. // Default to load their first site, but let the query string override it
  22. $role = ORM::for_table('roles')->join('sites', 'roles.site_id = sites.id')
  23. ->where('user_id', session('user_id'))->order_by_asc('sites.created_at')->find_one();
  24. if($request->get('account')) {
  25. $role = ORM::for_table('roles')->where('user_id', session('user_id'))->where('site_id', $request->get('account'))->find_one();
  26. // Check that the user has permission to access this account
  27. if(!$role) {
  28. $response->setStatusCode(302);
  29. $response->headers->set('Location', '/dashboard');
  30. return false;
  31. }
  32. }
  33. return $role;
  34. }
  35. public function index(Request $request, Response $response) {
  36. $response->setContent(view('index', [
  37. 'title' => 'Telegraph'
  38. ]));
  39. return $response;
  40. }
  41. public function api(Request $request, Response $response) {
  42. session_start();
  43. if(session('user_id')) {
  44. $role = $this->_get_role($request, $response);
  45. $site = ORM::for_table('sites')->where_id_is($role->site_id)->find_one();
  46. } else {
  47. $role = false;
  48. $site = false;
  49. }
  50. $response->setContent(view('api', [
  51. 'title' => 'Telegraph API Documentation',
  52. 'user' => $this->_user(),
  53. 'accounts' => $this->_accounts(),
  54. 'site' => $site,
  55. 'role' => $role,
  56. 'return_to' => $request->getRequestURI()
  57. ]));
  58. return $response;
  59. }
  60. private static function _icon_for_status($status) {
  61. switch($status) {
  62. case 'success':
  63. case 'accepted':
  64. return 'green checkmark';
  65. case 'not_supported':
  66. return 'yellow x';
  67. case 'error':
  68. return 'red x';
  69. case 'pending':
  70. return 'orange wait';
  71. default:
  72. return '';
  73. }
  74. }
  75. public function dashboard(Request $request, Response $response) {
  76. if(!$this->_is_logged_in($request, $response)) {
  77. return $response;
  78. }
  79. if(!$role=$this->_get_role($request, $response)) {
  80. return $response;
  81. }
  82. $site = ORM::for_table('sites')->where_id_is($role->site_id)->find_one();
  83. $query = ORM::for_table('webmentions')->where('site_id', $site->id)
  84. ->order_by_desc('created_at')
  85. ->limit(20)
  86. ->find_many();
  87. $webmentions = [];
  88. foreach($query as $m) {
  89. $statuses = ORM::for_table('webmention_status')->where('webmention_id', $m->id)->order_by_desc('created_at')->find_many();
  90. if(count($statuses) == 0) {
  91. $status = 'pending';
  92. } else {
  93. $status = $statuses[0]->status;
  94. }
  95. $icon = self::_icon_for_status($status);
  96. $webmentions[] = [
  97. 'webmention' => $m,
  98. 'statuses' => $statuses,
  99. 'status' => $status,
  100. 'icon' => $icon
  101. ];
  102. }
  103. $response->setContent(view('dashboard', [
  104. 'title' => 'Telegraph Dashboard',
  105. 'user' => $this->_user(),
  106. 'accounts' => $this->_accounts(),
  107. 'site' => $site,
  108. 'role' => $role,
  109. 'webmentions' => $webmentions
  110. ]));
  111. return $response;
  112. }
  113. public function webmention_details(Request $request, Response $response, $args) {
  114. if(!$this->_is_logged_in($request, $response)) {
  115. return $response;
  116. }
  117. // Look up the webmention by its token
  118. $webmention = ORM::for_table('webmentions')->where('token', $args['code'])->find_one();
  119. if(!$webmention) {
  120. $response->setContent(view('not-found'));
  121. return $response;
  122. }
  123. $site = ORM::for_table('sites')->where_id_is($webmention->site_id)->find_one();
  124. $statuses = ORM::for_table('webmention_status')->where('webmention_id', $webmention->id)->order_by_desc('created_at')->find_many();
  125. if(count($statuses) == 0) {
  126. $status = 'pending';
  127. } else {
  128. $status = $statuses[0]->status;
  129. }
  130. $icon = self::_icon_for_status($status);
  131. $response->setContent(view('webmention-details', [
  132. 'title' => 'Webmention Details',
  133. 'user' => $this->_user(),
  134. 'accounts' => $this->_accounts(),
  135. 'site' => $site,
  136. 'webmention' => $webmention,
  137. 'statuses' => $statuses,
  138. 'icon' => $icon,
  139. 'status' => $status
  140. ]));
  141. return $response;
  142. }
  143. public function dashboard_send(Request $request, Response $response) {
  144. if(!$this->_is_logged_in($request, $response)) {
  145. return $response;
  146. }
  147. if(!$role=$this->_get_role($request, $response)) {
  148. return $response;
  149. }
  150. $site = ORM::for_table('sites')->where_id_is($role->site_id)->find_one();
  151. $response->setContent(view('webmention-send', [
  152. 'title' => 'Webmention Details',
  153. 'user' => $this->_user(),
  154. 'accounts' => $this->_accounts(),
  155. 'site' => $site,
  156. 'role' => $role,
  157. 'url' => $request->get('url')
  158. ]));
  159. return $response;
  160. }
  161. public function get_outgoing_links(Request $request, Response $response) {
  162. if(!$this->_is_logged_in($request, $response)) {
  163. return $response;
  164. }
  165. $sourceURL = $request->get('url');
  166. $client = new IndieWeb\MentionClient();
  167. $source = $this->http->get($sourceURL);
  168. $parsed = \Mf2\parse($source['body'], $sourceURL);
  169. $links = array_values($client->findOutgoingLinks($parsed));
  170. $response->headers->set('Content-Type', 'application/json');
  171. $response->setContent(json_encode([
  172. 'links' => $links
  173. ]));
  174. return $response;
  175. }
  176. public function discover_endpoint(Request $request, Response $response) {
  177. if(!$this->_is_logged_in($request, $response)) {
  178. return $response;
  179. }
  180. $targetURL = $request->get('target');
  181. // Reject links that are known to not accept webmentions
  182. $host = str_replace('www.','',parse_url($targetURL, PHP_URL_HOST));
  183. $unsupported = [
  184. 'twitter.com',
  185. 'instagram.com',
  186. 'facebook.com',
  187. ];
  188. if(!$host || in_array($host, $unsupported) || preg_match('/.+\.amazonaws\.com/', $host)) {
  189. $status = 'none';
  190. $cached = -1;
  191. } else {
  192. // Cache the discovered result
  193. $cacheKey = 'telegraph:discover_endpoint:'.$targetURL;
  194. if($request->get('ignore_cache') == 'true' || (!$status = redis()->get($cacheKey))) {
  195. $client = new IndieWeb\MentionClient();
  196. $endpoint = $client->discoverWebmentionEndpoint($targetURL);
  197. if($endpoint) {
  198. $status = 'webmention';
  199. } else {
  200. $endpoint = $client->discoverPingbackEndpoint($targetURL);
  201. if($endpoint) {
  202. $status = 'pingback';
  203. } else {
  204. $status = 'none';
  205. }
  206. }
  207. $cached = false;
  208. redis()->setex($cacheKey, 600, $status);
  209. } else {
  210. $cached = true;
  211. }
  212. }
  213. $response->headers->set('Content-Type', 'application/json');
  214. $response->setContent(json_encode([
  215. 'status' => $status,
  216. 'cached' => $cached
  217. ]));
  218. return $response;
  219. }
  220. private function _user() {
  221. return ORM::for_table('users')->where_id_is(session('user_id'))->find_one();
  222. }
  223. private function _accounts() {
  224. return ORM::for_table('sites')->join('roles', 'roles.site_id = sites.id')
  225. ->where('roles.user_id', session('user_id'))
  226. ->find_many();
  227. }
  228. }