Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

AdminController.php 9.0 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <?php
  2. /**
  3. * @package Grav\Plugin\Admin
  4. *
  5. * @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. declare(strict_types=1);
  9. namespace Grav\Plugin\Admin\Controllers;
  10. use Grav\Common\Config\Config;
  11. use Grav\Common\Data\Blueprint;
  12. use Grav\Common\Grav;
  13. use Grav\Common\Language\Language;
  14. use Grav\Common\Page\Interfaces\PageInterface;
  15. use Grav\Common\Page\Page;
  16. use Grav\Common\Page\Pages;
  17. use Grav\Common\Uri;
  18. use Grav\Common\User\Interfaces\UserInterface;
  19. use Grav\Common\Utils;
  20. use Grav\Framework\Controller\Traits\ControllerResponseTrait;
  21. use Grav\Framework\RequestHandler\Exception\PageExpiredException;
  22. use Grav\Framework\Session\SessionInterface;
  23. use Grav\Plugin\Admin\Admin;
  24. use Grav\Plugin\Admin\AdminForm;
  25. use Psr\Http\Message\ResponseInterface;
  26. use Psr\Http\Message\ServerRequestInterface;
  27. use RocketTheme\Toolbox\Session\Message;
  28. abstract class AdminController
  29. {
  30. use ControllerResponseTrait {
  31. createRedirectResponse as traitCreateRedirectResponse;
  32. getErrorJson as traitGetErrorJson;
  33. }
  34. /** @var string */
  35. protected $nonce_action = 'admin-form';
  36. /** @var string */
  37. protected $nonce_name = 'admin-nonce';
  38. /** @var Grav */
  39. protected $grav;
  40. /** @var PageInterface */
  41. protected $page;
  42. /** @var AdminForm|null */
  43. protected $form;
  44. public function __construct(Grav $grav)
  45. {
  46. $this->grav = $grav;
  47. }
  48. /**
  49. * @return PageInterface|null
  50. */
  51. public function getPage(): ?PageInterface
  52. {
  53. return $this->page;
  54. }
  55. /**
  56. * Get currently active form.
  57. *
  58. * @return AdminForm|null
  59. */
  60. public function getActiveForm(): ?AdminForm
  61. {
  62. if (null === $this->form) {
  63. $post = $this->getPost();
  64. $active = $post['__form-name__'] ?? null;
  65. $this->form = $active ? $this->getForm($active) : null;
  66. }
  67. return $this->form;
  68. }
  69. /**
  70. * Get a form.
  71. *
  72. * @param string $name
  73. * @param array $options
  74. * @return AdminForm|null
  75. */
  76. public function getForm(string $name, array $options = []): ?AdminForm
  77. {
  78. $post = $this->getPost();
  79. $page = $this->getPage();
  80. $forms = $page ? $page->forms() : [];
  81. $blueprint = $forms[$name] ?? null;
  82. if (null === $blueprint) {
  83. return null;
  84. }
  85. $active = $post['__form-name__'] ?? null;
  86. $unique_id = $active && $active === $name ? ($post['__unique_form_id__'] ?? null) : null;
  87. $options += [
  88. 'unique_id' => $unique_id,
  89. 'blueprint' => new Blueprint(null, ['form' => $blueprint]),
  90. 'submit_method' => $this->getFormSubmitMethod($name),
  91. 'nonce_name' => $this->nonce_name,
  92. 'nonce_action' => $this->nonce_action,
  93. ];
  94. return new AdminForm($name, $options);
  95. }
  96. abstract protected function getFormSubmitMethod(string $name): callable;
  97. /**
  98. * @param string $route
  99. * @param string|null $lang
  100. * @return string
  101. */
  102. public function getAdminUrl(string $route, string $lang = null): string
  103. {
  104. /** @var Pages $pages */
  105. $pages = $this->grav['pages'];
  106. $admin = $this->getAdmin();
  107. return $pages->baseUrl($lang) . $admin->base . $route;
  108. }
  109. /**
  110. * @param string $route
  111. * @param string|null $lang
  112. * @return string
  113. */
  114. public function getAbsoluteAdminUrl(string $route, string $lang = null): string
  115. {
  116. /** @var Pages $pages */
  117. $pages = $this->grav['pages'];
  118. $admin = $this->getAdmin();
  119. return $pages->baseUrl($lang, true) . $admin->base . $route;
  120. }
  121. /**
  122. * Get session.
  123. *
  124. * @return SessionInterface
  125. */
  126. public function getSession(): SessionInterface
  127. {
  128. return $this->grav['session'];
  129. }
  130. /**
  131. * @return Admin
  132. */
  133. protected function getAdmin(): Admin
  134. {
  135. return $this->grav['admin'];
  136. }
  137. /**
  138. * @return UserInterface
  139. */
  140. protected function getUser(): UserInterface
  141. {
  142. return $this->getAdmin()->user;
  143. }
  144. /**
  145. * @return ServerRequestInterface
  146. */
  147. public function getRequest(): ServerRequestInterface
  148. {
  149. return $this->getAdmin()->request;
  150. }
  151. /**
  152. * @return array
  153. */
  154. public function getPost(): array
  155. {
  156. return (array)($this->getRequest()->getParsedBody() ?? []);
  157. }
  158. /**
  159. * Translate a string.
  160. *
  161. * @param string $string
  162. * @param mixed ...$args
  163. * @return string
  164. */
  165. public function translate(string $string, ...$args): string
  166. {
  167. /** @var Language $language */
  168. $language = $this->grav['language'];
  169. array_unshift($args, $string);
  170. return $language->translate($args);
  171. }
  172. /**
  173. * Set message to be shown in the admin.
  174. *
  175. * @param string $message
  176. * @param string $type
  177. * @return $this
  178. */
  179. public function setMessage(string $message, string $type = 'info'): AdminController
  180. {
  181. /** @var Message $messages */
  182. $messages = $this->grav['messages'];
  183. $messages->add($message, $type);
  184. return $this;
  185. }
  186. /**
  187. * @return Config
  188. */
  189. protected function getConfig(): Config
  190. {
  191. return $this->grav['config'];
  192. }
  193. /**
  194. * Check if request nonce is valid.
  195. *
  196. * @return void
  197. * @throws PageExpiredException If nonce is not valid.
  198. */
  199. protected function checkNonce(): void
  200. {
  201. $nonce = null;
  202. $nonce_name = $this->form ? $this->form->getNonceName() : $this->nonce_name;
  203. $nonce_action = $this->form ? $this->form->getNonceAction() : $this->nonce_action;
  204. if (\in_array(strtoupper($this->getRequest()->getMethod()), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
  205. $post = $this->getPost();
  206. $nonce = $post[$nonce_name] ?? null;
  207. }
  208. /** @var Uri $uri */
  209. $uri = $this->grav['uri'];
  210. if (!$nonce) {
  211. $nonce = $uri->param($nonce_name);
  212. }
  213. if (!$nonce) {
  214. $nonce = $uri->query($nonce_name);
  215. }
  216. if (!$nonce || !Utils::verifyNonce($nonce, $nonce_action)) {
  217. throw new PageExpiredException($this->getRequest());
  218. }
  219. }
  220. /**
  221. * Return the best matching mime type for the request.
  222. *
  223. * @param string[] $compare
  224. * @return string|null
  225. */
  226. protected function getAccept(array $compare): ?string
  227. {
  228. $accepted = [];
  229. foreach ($this->getRequest()->getHeader('Accept') as $accept) {
  230. foreach (explode(',', $accept) as $item) {
  231. if (!$item) {
  232. continue;
  233. }
  234. $split = explode(';q=', $item);
  235. $mime = array_shift($split);
  236. $priority = array_shift($split) ?? 1.0;
  237. $accepted[$mime] = $priority;
  238. }
  239. }
  240. arsort($accepted);
  241. // TODO: add support for image/* etc
  242. $list = array_intersect($compare, array_keys($accepted));
  243. if (!$list && (isset($accepted['*/*']) || isset($accepted['*']))) {
  244. return reset($compare) ?: null;
  245. }
  246. return reset($list) ?: null;
  247. }
  248. /**
  249. * @param string $template
  250. * @return PageInterface
  251. */
  252. protected function createPage(string $template): PageInterface
  253. {
  254. $page = new Page();
  255. // Plugins may not have the correct Cache-Control header set, force no-store for the proxies.
  256. $page->expires(0);
  257. $filename = "plugin://admin/pages/admin/{$template}.md";
  258. if (!file_exists($filename)) {
  259. throw new \RuntimeException(sprintf('Creating admin page %s failed: not found', $template));
  260. }
  261. Admin::DEBUG && Admin::addDebugMessage("Admin page: {$template}");
  262. $page->init(new \SplFileInfo($filename));
  263. $page->slug($template);
  264. return $page;
  265. }
  266. /**
  267. * @param string|null $url
  268. * @param int|null $code
  269. * @return ResponseInterface
  270. */
  271. protected function createRedirectResponse(string $url = null, int $code = null): ResponseInterface
  272. {
  273. $request = $this->getRequest();
  274. if (null === $url || '' === $url) {
  275. $url = (string)$request->getUri();
  276. } elseif (mb_strpos($url, '/') === 0) {
  277. $url = $this->getAbsoluteAdminUrl($url);
  278. }
  279. if (null === $code) {
  280. if (in_array($request->getMethod(), ['GET', 'HEAD'])) {
  281. $code = 302;
  282. } else {
  283. $code = 303;
  284. }
  285. }
  286. return $this->traitCreateRedirectResponse($url, $code);
  287. }
  288. /**
  289. * @param \Throwable $e
  290. * @return array
  291. */
  292. protected function getErrorJson(\Throwable $e): array
  293. {
  294. $json = $this->traitGetErrorJson($e);
  295. $code = $e->getCode();
  296. if ($code === 401) {
  297. $json['redirect'] = $this->getAbsoluteAdminUrl('/');
  298. }
  299. return $json;
  300. }
  301. }