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.

318 lines
10 KiB

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Laravel\Lumen\Routing\Controller as BaseController;
  4. use Illuminate\Http\Request;
  5. use DB;
  6. class Controller extends BaseController
  7. {
  8. private static function displayURL() {
  9. return preg_replace('/(^https?:\/\/|\/$)/', '', session('me'));
  10. }
  11. public function index(Request $request) {
  12. if(session('user_id')) {
  13. $databases = DB::select('SELECT d.*
  14. FROM `databases` d
  15. JOIN database_users u ON d.id = u.database_id
  16. WHERE u.user_id = ?
  17. ORDER BY name', [session('user_id')]);
  18. return view('dashboard', [
  19. 'displayURL' => self::displayURL(),
  20. 'databases' => $databases
  21. ]);
  22. } else {
  23. return view('index');
  24. }
  25. }
  26. public function createDatabase(Request $request) {
  27. if(!session('user_id'))
  28. return redirect('/');
  29. if($request->input('name') == '') {
  30. $request->session()->flash('create-error', 'Enter a name.');
  31. return redirect('/');
  32. }
  33. // Only alphanumeric chars are allowed
  34. if(preg_replace('/[^a-zA-Z0-9]/', '', $request->input('name')) != $request->input('name')) {
  35. $request->session()->flash('create-error', 'Only alphanumeric characters are allowed.');
  36. $request->session()->flash('database-name', preg_replace('/[^a-zA-Z0-9]/','',$request->input('name')));
  37. return redirect('/');
  38. }
  39. // Check for conflicts
  40. $db = DB::select('SELECT * FROM `databases` WHERE name = ?', [$request->input('name')]);
  41. if(count($db) == 0) {
  42. // Create the database records
  43. $id = DB::table('databases')->insertGetId([
  44. 'name' => $request->input('name'),
  45. 'read_token' => str_random(40),
  46. 'write_token' => str_random(40),
  47. 'created_by' => session('user_id'),
  48. 'created_at' => date('Y-m-d H:i:s')
  49. ]);
  50. DB::table('database_users')->insert([
  51. 'database_id' => $id,
  52. 'user_id' => session('user_id'),
  53. 'created_at' => date('Y-m-d H:i:s')
  54. ]);
  55. return redirect('/');
  56. } else {
  57. $request->session()->flash('create-error', 'That database name is already in use.');
  58. $request->session()->flash('database-name', $request->input('name'));
  59. return redirect('/');
  60. }
  61. }
  62. public function map(Request $request, $name) {
  63. if(!session('user_id'))
  64. return redirect('/');
  65. // Verify this user has access to the database
  66. $db = DB::table('databases')
  67. ->join('database_users', function($join){
  68. $join->on('databases.id','=','database_users.database_id');
  69. })
  70. ->where('user_id','=',session('user_id'))
  71. ->where('name','=',$name)
  72. ->first();
  73. if(!$db)
  74. return redirect('/');
  75. return view('map', [
  76. 'displayURL' => self::displayURL(),
  77. 'database' => $db,
  78. 'menu' => [
  79. '/settings/'.$name => 'Settings'
  80. ],
  81. 'range_from' => $request->input('from') ?: '',
  82. 'range_to' => $request->input('to') ?: '',
  83. 'range_tz' => $request->input('tz') ?: $db->timezone
  84. ]);
  85. }
  86. public function settings(Request $request, $name) {
  87. if(!session('user_id'))
  88. return redirect('/');
  89. // Only the person that created the database can modify it
  90. $db = DB::table('databases')
  91. ->where('created_by','=',session('user_id'))
  92. ->where('name','=',$name)
  93. ->first();
  94. if(!$db)
  95. return redirect('/');
  96. $users = DB::select('SELECT u.*
  97. FROM users u
  98. JOIN database_users d ON u.id = d.user_id
  99. WHERE d.database_id = ?
  100. ORDER BY u.url', [$db->id]);
  101. return view('settings', [
  102. 'displayURL' => self::displayURL(),
  103. 'database' => $db,
  104. 'users' => $users,
  105. 'menu' => [
  106. '/map/'.$name => 'Map'
  107. ]
  108. ]);
  109. }
  110. public function updateSettings(Request $request, $name) {
  111. if(!session('user_id'))
  112. return redirect('/');
  113. // Only the person that created the database can modify it
  114. $db = DB::table('databases')
  115. ->where('created_by','=',session('user_id'))
  116. ->where('name','=',$name)
  117. ->first();
  118. if(!$db)
  119. return redirect('/');
  120. if($request->input('remove_user')) {
  121. $user = DB::table('users')->where('url','=',$request->input('remove_user'))->first();
  122. if($user) {
  123. DB::table('database_users')->where('database_id','=',$db->id)->where('user_id','=',$user->id)->delete();
  124. }
  125. return response(json_encode([
  126. 'result' => 'ok'
  127. ]))->header('Content-Type', 'application/json');
  128. } else if($request->input('add_user')) {
  129. // Find user if it exists already
  130. $user = DB::table('users')->where('url','=',$request->input('add_user'))->first();
  131. if($user) {
  132. $user_id = $user->id;
  133. } else {
  134. $user_id = DB::table('users')->insertGetId([
  135. 'url' => $request->input('add_user'),
  136. 'created_at' => date('Y-m-d H:i:s')
  137. ]);
  138. }
  139. // Add access to the database
  140. $exists = DB::table('database_users')->where('database_id','=',$db->id)->where('user_id','=',$user_id)->first();
  141. if(!$exists) {
  142. DB::table('database_users')->insert([
  143. 'database_id' => $db->id,
  144. 'user_id' => $user_id,
  145. 'created_at' => date('Y-m-d H:i:s')
  146. ]);
  147. }
  148. return redirect('/settings/'.$db->name);
  149. } else if($request->input('micropub_endpoint')) {
  150. DB::table('databases')->where('id', $db->id)
  151. ->update([
  152. 'micropub_endpoint' => $request->input('micropub_endpoint'),
  153. 'micropub_token' => $request->input('micropub_token'),
  154. ]);
  155. return redirect('/settings/'.$db->name);
  156. } else if($request->input('ping_urls')) {
  157. DB::table('databases')->where('id', $db->id)
  158. ->update([
  159. 'ping_urls' => $request->input('ping_urls'),
  160. ]);
  161. return redirect('/settings/'.$db->name);
  162. } else if($request->input('timezone')) {
  163. DB::table('databases')->where('id', $db->id)
  164. ->update([
  165. 'timezone' => $request->input('timezone'),
  166. 'metric' => $request->input('metric'),
  167. ]);
  168. return redirect('/settings/'.$db->name);
  169. }
  170. }
  171. public function micropubStart(Request $request, $dbName) {
  172. $me = \IndieAuth\Client::normalizeMeURL($request->input('me'));
  173. if(!$me) {
  174. return view('auth/error', ['error' => 'Invalid URL']);
  175. }
  176. $state = \IndieAuth\Client::generateStateParameter();
  177. $authorizationEndpoint = \IndieAuth\Client::discoverAuthorizationEndpoint($me);
  178. // Isolate session variables to this variable only
  179. session([$dbName => [
  180. 'auth_state' => $state,
  181. 'attempted_me' => $me,
  182. 'authorization_endpoint' => $authorizationEndpoint
  183. ]]);
  184. // If the user specified only an authorization endpoint, use that
  185. if(!$authorizationEndpoint) {
  186. // Otherwise, fall back to indieauth.com
  187. $authorizationEndpoint = env('DEFAULT_AUTH_ENDPOINT');
  188. }
  189. $authorizationURL = \IndieAuth\Client::buildAuthorizationURL($authorizationEndpoint, $me, $this->_databaseRedirectURI($dbName), env('BASE_URL'), $state, 'create');
  190. return redirect($authorizationURL);
  191. }
  192. public function micropubCallback(Request $request, $dbName) {
  193. $settingsSession = session($dbName);
  194. // Start all error checking
  195. if(!$settingsSession['auth_state'] || !$settingsSession['attempted_me']) {
  196. return view('auth/error', ['error' => 'Missing state information. Start over.']);
  197. }
  198. if($request->input('error')) {
  199. return view('auth/error', ['error' => $request->input('error')]);
  200. }
  201. if($settingsSession['auth_state'] != $request->input('state')) {
  202. return view('auth/error', ['error' => 'State did not match. Start over.']);
  203. }
  204. // Verify that the database exists and doesn't have micropub already
  205. $db = DB::table('databases')
  206. ->where('name','=',$dbName)
  207. ->first();
  208. if (!$db) {
  209. return view('auth/error', ['error' => 'Database requested does not exist']);
  210. }
  211. if (!empty($db->micropub_token)) {
  212. return view('auth/error', ['error' => 'Database already is connected to a micropub endpoint. Please remove the existing endpoint first.']);
  213. }
  214. $tokenEndpoint = \IndieAuth\Client::discoverTokenEndpoint($settingsSession['attempted_me']);
  215. if (empty($tokenEndpoint)) {
  216. return view('auth/error', ['error' => 'Could not find user\'s token endpoint']);
  217. }
  218. $token = \IndieAuth\Client::getAccessToken($tokenEndpoint, $request->input('code'), $settingsSession['attempted_me'], $this->_databaseRedirectURI($dbName), env('BASE_URL'));
  219. if($token && array_key_exists('me', $token)) {
  220. // forget the current db settings session
  221. session()->forget($dbName);
  222. if (!array_key_exists('access_token', $token)) {
  223. return view('auth/error', ['error' => 'Could not find access_token']);
  224. }
  225. if (!array_key_exists('scope', $token) || strpos($token['scope'], 'create') === false) {
  226. return view('auth/error', ['error' => 'You were not granted a create scope']);
  227. }
  228. $micropubEndpoint = \IndieAuth\Client::discoverMicropubEndpoint($token['me']);
  229. $micropubToken = $token['access_token'];
  230. DB::table('databases')->where('id', $db->id)
  231. ->update([
  232. 'micropub_endpoint' => $micropubEndpoint,
  233. 'micropub_token' => $micropubToken
  234. ]);
  235. } else {
  236. return view('auth/error', ['error' => 'No url id found']);
  237. }
  238. return redirect('/settings/'.$db->name);
  239. }
  240. public function removeMicropub(Request $request, $dbName) {
  241. $db = DB::table('databases')
  242. ->where('name','=',$dbName)
  243. ->first();
  244. if (!$db) {
  245. return view('auth/error', ['error' => 'Database requested does not exist']);
  246. }
  247. DB::table('databases')->where('id', $db->id)
  248. ->update([
  249. 'micropub_endpoint' => '',
  250. 'micropub_token' => ''
  251. ]);
  252. return redirect('/settings/'.$db->name);
  253. }
  254. private function _databaseRedirectURI($dbName) {
  255. return env('BASE_URL') . 'settings/' . $dbName . '/auth/callback';
  256. }
  257. }