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.

348 lines
9.9 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. public function superfeedr(Request $request, Response $response) {
  61. session_start();
  62. if(session('user_id')) {
  63. $role = $this->_get_role($request, $response);
  64. $site = ORM::for_table('sites')->where_id_is($role->site_id)->find_one();
  65. } else {
  66. $role = false;
  67. $site = false;
  68. }
  69. $response->setContent(view('superfeedr', [
  70. 'title' => 'Telegraph Superfeedr Documentation',
  71. 'user' => $this->_user(),
  72. 'accounts' => $this->_accounts(),
  73. 'site' => $site,
  74. 'role' => $role,
  75. 'return_to' => $request->getRequestURI()
  76. ]));
  77. return $response;
  78. }
  79. private static function _icon_for_status($status) {
  80. switch($status) {
  81. case 'success':
  82. case 'accepted':
  83. return 'green checkmark';
  84. case 'not_supported':
  85. return 'yellow x';
  86. case 'error':
  87. return 'red x';
  88. case 'pending':
  89. return 'orange wait';
  90. default:
  91. return '';
  92. }
  93. }
  94. public function dashboard(Request $request, Response $response) {
  95. if(!$this->_is_logged_in($request, $response)) {
  96. return $response;
  97. }
  98. if(!$role=$this->_get_role($request, $response)) {
  99. return $response;
  100. }
  101. $site = ORM::for_table('sites')->where_id_is($role->site_id)->find_one();
  102. $query = ORM::for_table('webmentions')->where('site_id', $site->id)
  103. ->order_by_desc('created_at')
  104. ->limit(20)
  105. ->find_many();
  106. $webmentions = [];
  107. foreach($query as $m) {
  108. $statuses = ORM::for_table('webmention_status')->where('webmention_id', $m->id)->order_by_desc('created_at')->find_many();
  109. if(count($statuses) == 0) {
  110. $status = 'pending';
  111. } else {
  112. $status = $statuses[0]->status;
  113. }
  114. $icon = self::_icon_for_status($status);
  115. $webmentions[] = [
  116. 'webmention' => $m,
  117. 'statuses' => $statuses,
  118. 'status' => $status,
  119. 'icon' => $icon
  120. ];
  121. }
  122. $response->setContent(view('dashboard', [
  123. 'title' => 'Telegraph Dashboard',
  124. 'user' => $this->_user(),
  125. 'accounts' => $this->_accounts(),
  126. 'site' => $site,
  127. 'role' => $role,
  128. 'webmentions' => $webmentions
  129. ]));
  130. return $response;
  131. }
  132. public function new_site(Request $request, Response $response) {
  133. if(!$this->_is_logged_in($request, $response)) {
  134. return $response;
  135. }
  136. if(!$role=$this->_get_role($request, $response)) {
  137. return $response;
  138. }
  139. if($request->get('account')) {
  140. // permissions are checked already by _get_role
  141. $site = ORM::for_table('sites')->where_id_is($request->get('account'))->find_one();
  142. } else {
  143. $site = null;
  144. }
  145. $response->setContent(view('new-site', [
  146. 'title' => 'Create New Site',
  147. 'user' => $this->_user(),
  148. 'accounts' => $this->_accounts(),
  149. 'role' => $role,
  150. 'site' => $site
  151. ]));
  152. return $response;
  153. }
  154. public function save_site(Request $request, Response $response) {
  155. if(!$this->_is_logged_in($request, $response)) {
  156. return $response;
  157. }
  158. if(!$role=$this->_get_role($request, $response)) {
  159. return $response;
  160. }
  161. if($request->get('account')) {
  162. // permissions are checked already by _get_role
  163. $site = ORM::for_table('sites')->where_id_is($request->get('account'))->find_one();
  164. $site->name = $request->get('name');
  165. $site->url = $request->get('url');
  166. $site->save();
  167. } else {
  168. $site = ORM::for_table('sites')->create();
  169. $site->created_by = session('user_id');
  170. $site->created_at = date('Y-m-d H:i:s');
  171. $site->name = $request->get('name');
  172. $site->url = $request->get('url');
  173. $site->save();
  174. $role = ORM::for_table('roles')->create();
  175. $role->site_id = $site->id;
  176. $role->user_id = session('user_id');
  177. $role->role = 'owner';
  178. $role->token = random_string(32);
  179. $role->save();
  180. }
  181. $response->setStatusCode(302);
  182. $response->headers->set('Location', '/dashboard?account='.$site->id);
  183. return $response;
  184. }
  185. public function webmention_details(Request $request, Response $response, $args) {
  186. session_start();
  187. // Look up the webmention by its token
  188. $webmention = ORM::for_table('webmentions')->where('token', $args['code'])->find_one();
  189. if(!$webmention) {
  190. $response->setContent(view('not-found'));
  191. return $response;
  192. }
  193. $site = ORM::for_table('sites')->where_id_is($webmention->site_id)->find_one();
  194. $statuses = ORM::for_table('webmention_status')->where('webmention_id', $webmention->id)->order_by_desc('created_at')->find_many();
  195. if(count($statuses) == 0) {
  196. $status = 'pending';
  197. } else {
  198. $status = $statuses[0]->status;
  199. }
  200. $icon = self::_icon_for_status($status);
  201. $response->setContent(view('webmention-details', [
  202. 'title' => 'Webmention Details',
  203. 'user' => $this->_user(),
  204. 'accounts' => $this->_accounts(),
  205. 'site' => $site,
  206. 'webmention' => $webmention,
  207. 'statuses' => $statuses,
  208. 'icon' => $icon,
  209. 'status' => $status
  210. ]));
  211. return $response;
  212. }
  213. public function dashboard_send(Request $request, Response $response) {
  214. if(!$this->_is_logged_in($request, $response)) {
  215. return $response;
  216. }
  217. if(!$role=$this->_get_role($request, $response)) {
  218. return $response;
  219. }
  220. $site = ORM::for_table('sites')->where_id_is($role->site_id)->find_one();
  221. $response->setContent(view('webmention-send', [
  222. 'title' => 'Webmention Details',
  223. 'user' => $this->_user(),
  224. 'accounts' => $this->_accounts(),
  225. 'site' => $site,
  226. 'role' => $role,
  227. 'url' => $request->get('url')
  228. ]));
  229. return $response;
  230. }
  231. public function get_outgoing_links(Request $request, Response $response) {
  232. if(!$this->_is_logged_in($request, $response)) {
  233. return $response;
  234. }
  235. $sourceURL = $request->get('url');
  236. $client = new IndieWeb\MentionClient();
  237. $source = $this->http->get($sourceURL, ['Accept: text/html, */*']);
  238. $parsed = \Mf2\parse($source['body'], $sourceURL);
  239. $links = array_values($client->findOutgoingLinks($parsed));
  240. // Remove the source URL from the list if present
  241. $links = array_filter($links, function($link) use($sourceURL) {
  242. return $link != $sourceURL;
  243. });
  244. $response->headers->set('Content-Type', 'application/json');
  245. $response->setContent(json_encode([
  246. 'links' => $links
  247. ]));
  248. return $response;
  249. }
  250. public function discover_endpoint(Request $request, Response $response) {
  251. if(!$this->_is_logged_in($request, $response)) {
  252. return $response;
  253. }
  254. $targetURL = $request->get('target');
  255. if(!Telegraph\Webmention::isProbablySupported($targetURL)) {
  256. $status = 'none';
  257. $cached = -1;
  258. } else {
  259. // Cache the discovered result
  260. $cacheKey = 'telegraph:discover_endpoint:'.$targetURL;
  261. if($request->get('ignore_cache') == 'true' || (!$status = redis()->get($cacheKey))) {
  262. $client = new IndieWeb\MentionClient();
  263. $endpoint = $client->discoverWebmentionEndpoint($targetURL);
  264. if($endpoint) {
  265. $status = 'webmention';
  266. } else {
  267. $endpoint = $client->discoverPingbackEndpoint($targetURL);
  268. if($endpoint) {
  269. $status = 'pingback';
  270. } else {
  271. $status = 'none';
  272. }
  273. }
  274. $cached = false;
  275. redis()->setex($cacheKey, 600, $status);
  276. } else {
  277. $cached = true;
  278. }
  279. }
  280. $response->headers->set('Content-Type', 'application/json');
  281. $response->setContent(json_encode([
  282. 'status' => $status,
  283. 'cached' => $cached
  284. ]));
  285. return $response;
  286. }
  287. private function _user() {
  288. if(!session('user_id')) return null;
  289. return ORM::for_table('users')->where_id_is(session('user_id'))->find_one();
  290. }
  291. private function _accounts() {
  292. return ORM::for_table('sites')->join('roles', 'roles.site_id = sites.id')
  293. ->where('roles.user_id', session('user_id'))
  294. ->find_many();
  295. }
  296. }