SettingsController.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. <?php
  2. namespace Typemill\Controllers;
  3. use \Symfony\Component\Yaml\Yaml;
  4. use Typemill\Models\Write;
  5. use Typemill\Models\Fields;
  6. use Typemill\Models\Validation;
  7. use Typemill\Models\User;
  8. use Typemill\Models\ProcessFile;
  9. use Typemill\Models\ProcessImage;
  10. class SettingsController extends Controller
  11. {
  12. /*********************
  13. ** BASIC SETTINGS **
  14. *********************/
  15. public function showSettings($request, $response, $args)
  16. {
  17. $user = new User();
  18. $settings = $this->c->get('settings');
  19. $defaultSettings = \Typemill\Settings::getDefaultSettings();
  20. $copyright = $this->getCopyright();
  21. $languages = $this->getLanguages();
  22. $locale = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? substr($_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2) : 'en';
  23. $users = $user->getUsers();
  24. $route = $request->getAttribute('route');
  25. return $this->render($response, 'settings/system.twig', array('settings' => $settings, 'copyright' => $copyright, 'languages' => $languages, 'locale' => $locale, 'formats' => $defaultSettings['formats'] ,'users' => $users, 'route' => $route->getName() ));
  26. }
  27. public function saveSettings($request, $response, $args)
  28. {
  29. if($request->isPost())
  30. {
  31. $referer = $request->getHeader('HTTP_REFERER');
  32. $uri = $request->getUri()->withUserInfo('');
  33. $base_url = $uri->getBaseUrl();
  34. /* security, users should not be able to fake post with settings from other typemill pages.
  35. if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/settings' )
  36. {
  37. $this->c->flash->addMessage('error', 'illegal referer');
  38. return $response->withRedirect($this->c->router->pathFor('settings.show'));
  39. }
  40. */
  41. $settings = \Typemill\Settings::getUserSettings();
  42. $defaultSettings = \Typemill\Settings::getDefaultSettings();
  43. $params = $request->getParams();
  44. $files = $request->getUploadedFiles();
  45. $newSettings = isset($params['settings']) ? $params['settings'] : false;
  46. $validate = new Validation();
  47. $processFiles = new ProcessFile();
  48. if($newSettings)
  49. {
  50. /* make sure only allowed fields are stored */
  51. $newSettings = array(
  52. 'title' => $newSettings['title'],
  53. 'author' => $newSettings['author'],
  54. 'copyright' => $newSettings['copyright'],
  55. 'year' => $newSettings['year'],
  56. 'language' => $newSettings['language'],
  57. 'langattr' => $newSettings['langattr'],
  58. 'editor' => $newSettings['editor'],
  59. 'formats' => $newSettings['formats'],
  60. 'headlineanchors' => isset($newSettings['headlineanchors']) ? $newSettings['headlineanchors'] : null,
  61. );
  62. # https://www.slimframework.com/docs/v3/cookbook/uploading-files.html;
  63. $copyright = $this->getCopyright();
  64. $validate->settings($newSettings, $copyright, $defaultSettings['formats'], 'settings');
  65. }
  66. else
  67. {
  68. $this->c->flash->addMessage('error', 'Wrong Input');
  69. return $response->withRedirect($this->c->router->pathFor('settings.show'));
  70. }
  71. if(isset($_SESSION['errors']))
  72. {
  73. $this->c->flash->addMessage('error', 'Please correct the errors');
  74. return $response->withRedirect($this->c->router->pathFor('settings.show'));
  75. }
  76. if(!$processFiles->checkFolders())
  77. {
  78. $this->c->flash->addMessage('error', 'Please make sure that your media folder exists and is writable.');
  79. return $response->withRedirect($this->c->router->pathFor('settings.show'));
  80. }
  81. # handle single input with single file upload
  82. $logo = $files['settings']['logo'];
  83. if($logo->getError() === UPLOAD_ERR_OK)
  84. {
  85. $allowed = ['jpg', 'jpeg', 'png', 'svg'];
  86. $extension = pathinfo($logo->getClientFilename(), PATHINFO_EXTENSION);
  87. if(!in_array(strtolower($extension), $allowed))
  88. {
  89. $_SESSION['errors']['settings']['logo'] = array('Only jpg, jpeg, png and svg allowed');
  90. $this->c->flash->addMessage('error', 'Please correct the errors');
  91. return $response->withRedirect($this->c->router->pathFor('settings.show'));
  92. }
  93. $processFiles->deleteFileWithName('logo');
  94. $newSettings['logo'] = $processFiles->moveUploadedFile($logo, $overwrite = true, $name = 'logo');
  95. }
  96. elseif(isset($params['settings']['deletelogo']) && $params['settings']['deletelogo'] == 'delete')
  97. {
  98. $processFiles->deleteFileWithName('logo');
  99. $newSettings['logo'] = '';
  100. }
  101. else
  102. {
  103. $newSettings['logo'] = isset($settings['logo']) ? $settings['logo'] : '';
  104. }
  105. # handle single input with single file upload
  106. $favicon = $files['settings']['favicon'];
  107. if ($favicon->getError() === UPLOAD_ERR_OK)
  108. {
  109. $extension = pathinfo($favicon->getClientFilename(), PATHINFO_EXTENSION);
  110. if(strtolower($extension) != 'png')
  111. {
  112. $_SESSION['errors']['settings']['favicon'] = array('Only .png-files allowed');
  113. $this->c->flash->addMessage('error', 'Please correct the errors');
  114. return $response->withRedirect($this->c->router->pathFor('settings.show'));
  115. }
  116. $processImage = new ProcessImage([
  117. '16' => ['width' => 16, 'height' => 16],
  118. '32' => ['width' => 32, 'height' => 32],
  119. '72' => ['width' => 72, 'height' => 72],
  120. '114' => ['width' => 114, 'height' => 114],
  121. '144' => ['width' => 144, 'height' => 144],
  122. '180' => ['width' => 180, 'height' => 180],
  123. ]);
  124. $favicons = $processImage->generateSizesFromImageFile('favicon.png', $favicon->file);
  125. foreach($favicons as $key => $favicon)
  126. {
  127. imagepng( $favicon, $processFiles->fileFolder . 'favicon-' . $key . '.png' );
  128. # $processFiles->moveUploadedFile($favicon, $overwrite = true, $name = 'favicon-' . $key);
  129. }
  130. $newSettings['favicon'] = 'favicon';
  131. }
  132. elseif(isset($params['settings']['deletefav']) && $params['settings']['deletefav'] == 'delete')
  133. {
  134. $processFiles->deleteFileWithName('favicon');
  135. $newSettings['favicon'] = '';
  136. }
  137. else
  138. {
  139. $newSettings['favicon'] = isset($settings['favicon']) ? $settings['favicon'] : '';
  140. }
  141. # store updated settings
  142. \Typemill\Settings::updateSettings(array_merge($settings, $newSettings));
  143. $this->c->flash->addMessage('info', 'Settings are stored');
  144. return $response->withRedirect($this->c->router->pathFor('settings.show'));
  145. }
  146. }
  147. /*********************
  148. ** THEME SETTINGS **
  149. *********************/
  150. public function showThemes($request, $response, $args)
  151. {
  152. $userSettings = $this->c->get('settings');
  153. $themes = $this->getThemes();
  154. $themedata = array();
  155. $fieldsModel = new Fields();
  156. foreach($themes as $themeName)
  157. {
  158. /* if theme is active, list it first */
  159. if($userSettings['theme'] == $themeName)
  160. {
  161. $themedata = array_merge(array($themeName => null), $themedata);
  162. }
  163. else
  164. {
  165. $themedata[$themeName] = null;
  166. }
  167. $themeSettings = \Typemill\Settings::getObjectSettings('themes', $themeName);
  168. # add standard-textarea for custom css
  169. $themeSettings['forms']['fields']['customcss'] = ['type' => 'textarea', 'label' => 'Custom CSS', 'rows' => 10, 'class' => 'codearea', 'description' => 'You can overwrite the theme-css with your own css here.'];
  170. # load custom css-file
  171. $write = new write();
  172. $customcss = $write->getFile('cache', $themeName . '-custom.css');
  173. $themeSettings['settings']['customcss'] = $customcss;
  174. if($themeSettings)
  175. {
  176. /* store them as default theme data with author, year, default settings and field-definitions */
  177. $themedata[$themeName] = $themeSettings;
  178. }
  179. if(isset($themeSettings['forms']['fields']))
  180. {
  181. $fields = $fieldsModel->getFields($userSettings, 'themes', $themeName, $themeSettings);
  182. /* overwrite original theme form definitions with enhanced form objects */
  183. $themedata[$themeName]['forms']['fields'] = $fields;
  184. }
  185. /* add the preview image */
  186. $img = getcwd() . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $themeName . DIRECTORY_SEPARATOR . $themeName;
  187. $image = false;
  188. if(file_exists($img . '.jpg'))
  189. {
  190. $image = $themeName . '.jpg';
  191. }
  192. if(file_exists($img . '.png'))
  193. {
  194. $image = $themeName . '.png';
  195. }
  196. $themedata[$themeName]['img'] = $image;
  197. }
  198. /* add the users for navigation */
  199. $user = new User();
  200. $users = $user->getUsers();
  201. $route = $request->getAttribute('route');
  202. return $this->render($response, 'settings/themes.twig', array('settings' => $userSettings, 'themes' => $themedata, 'users' => $users, 'route' => $route->getName() ));
  203. }
  204. public function showPlugins($request, $response, $args)
  205. {
  206. $userSettings = $this->c->get('settings');
  207. $plugins = array();
  208. $fieldsModel = new Fields();
  209. $fields = array();
  210. /* iterate through the plugins in the stored user settings */
  211. foreach($userSettings['plugins'] as $pluginName => $pluginUserSettings)
  212. {
  213. /* add plugin to plugin Data, if active, set it first */
  214. /* if plugin is active, list it first */
  215. if($userSettings['plugins'][$pluginName]['active'] == true)
  216. {
  217. $plugins = array_merge(array($pluginName => null), $plugins);
  218. }
  219. else
  220. {
  221. $plugins[$pluginName] = Null;
  222. }
  223. /* Check if the user has deleted a plugin. Then delete it in the settings and store the updated settings. */
  224. if(!is_dir($userSettings['rootPath'] . 'plugins' . DIRECTORY_SEPARATOR . $pluginName))
  225. {
  226. /* remove the plugin settings and store updated settings */
  227. \Typemill\Settings::removePluginSettings($pluginName);
  228. continue;
  229. }
  230. /* load the original plugin definitions from the plugin folder (author, version and stuff) */
  231. $pluginOriginalSettings = \Typemill\Settings::getObjectSettings('plugins', $pluginName);
  232. if($pluginOriginalSettings)
  233. {
  234. /* store them as default plugin data with plugin author, plugin year, default settings and field-definitions */
  235. $plugins[$pluginName] = $pluginOriginalSettings;
  236. }
  237. /* check, if the plugin has been disabled in the form-session-data */
  238. if(isset($_SESSION['old']) && !isset($_SESSION['old'][$pluginName]['active']))
  239. {
  240. $plugins[$pluginName]['settings']['active'] = false;
  241. }
  242. /* if the plugin defines forms and fields, so that the user can edit the plugin settings in the frontend */
  243. if(isset($pluginOriginalSettings['forms']['fields']))
  244. {
  245. # if the plugin defines frontend fields
  246. if(isset($pluginOriginalSettings['public']))
  247. {
  248. $pluginOriginalSettings['forms']['fields']['recaptcha'] = ['type' => 'checkbox', 'label' => 'Google Recaptcha', 'checkboxlabel' => 'Activate Recaptcha' ];
  249. $pluginOriginalSettings['forms']['fields']['recaptcha_webkey'] = ['type' => 'text', 'label' => 'Recaptcha Website Key', 'help' => 'Add the recaptcha website key here. You can get the key from the recaptcha website.', 'description' => 'The website key is mandatory if you activate the recaptcha field'];
  250. $pluginOriginalSettings['forms']['fields']['recaptcha_secretkey'] = ['type' => 'text', 'label' => 'Recaptcha Secret Key', 'help' => 'Add the recaptcha secret key here. You can get the key from the recaptcha website.', 'description' => 'The secret key is mandatory if you activate the recaptcha field'];
  251. }
  252. /* get all the fields and prefill them with the dafault-data, the user-data or old input data */
  253. $fields = $fieldsModel->getFields($userSettings, 'plugins', $pluginName, $pluginOriginalSettings);
  254. /* overwrite original plugin form definitions with enhanced form objects */
  255. $plugins[$pluginName]['forms']['fields'] = $fields;
  256. }
  257. }
  258. $user = new User();
  259. $users = $user->getUsers();
  260. $route = $request->getAttribute('route');
  261. return $this->render($response, 'settings/plugins.twig', array('settings' => $userSettings, 'plugins' => $plugins, 'users' => $users, 'route' => $route->getName() ));
  262. }
  263. /*************************************
  264. ** SAVE THEME- AND PLUGIN-SETTINGS **
  265. *************************************/
  266. public function saveThemes($request, $response, $args)
  267. {
  268. if($request->isPost())
  269. {
  270. $referer = $request->getHeader('HTTP_REFERER');
  271. $uri = $request->getUri()->withUserInfo('');
  272. $base_url = $uri->getBaseUrl();
  273. /* users should not be able to fake post with settings from other typemill pages.
  274. if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/themes' )
  275. {
  276. $this->c->flash->addMessage('error', 'illegal referer');
  277. return $response->withRedirect($this->c->router->pathFor('themes.show'));
  278. }
  279. */
  280. $userSettings = \Typemill\Settings::getUserSettings();
  281. $params = $request->getParams();
  282. $themeName = isset($params['theme']) ? $params['theme'] : false;
  283. $userInput = isset($params[$themeName]) ? $params[$themeName] : false;
  284. $validate = new Validation();
  285. $themeSettings = \Typemill\Settings::getObjectSettings('themes', $themeName);
  286. if(isset($themeSettings['settings']['images']))
  287. {
  288. # get the default settings
  289. $defaultSettings = \Typemill\Settings::getDefaultSettings();
  290. # merge the default image settings with the theme image settings, delete all others (image settings from old theme)
  291. $userSettings['images'] = array_merge($defaultSettings['images'], $themeSettings['settings']['images']);
  292. }
  293. /* set theme name and delete theme settings from user settings for the case, that the new theme has no settings */
  294. $userSettings['theme'] = $themeName;
  295. # extract the custom css from user input
  296. $customcss = isset($userInput['customcss']) ? $userInput['customcss'] : false;
  297. # delete custom css from userinput
  298. unset($userInput['customcss']);
  299. $write = new write();
  300. # make sure no file is set if there is no custom css
  301. if(!$customcss OR $customcss == '')
  302. {
  303. # delete the css file if exists
  304. $write->deleteFileWithPath('cache' . DIRECTORY_SEPARATOR . $themeName . '-custom.css');
  305. }
  306. else
  307. {
  308. if ( $customcss != strip_tags($customcss) )
  309. {
  310. $_SESSION['errors'][$themeName]['customcss'][] = 'custom css contains html';
  311. }
  312. else
  313. {
  314. # store css
  315. $write = new write();
  316. $write->writeFile('cache', $themeName . '-custom.css', $customcss);
  317. }
  318. }
  319. if($userInput)
  320. {
  321. # validate the user-input and return image-fields if they are defined
  322. $imageFields = $this->validateInput('themes', $themeName, $userInput, $validate);
  323. /* set user input as theme settings */
  324. $userSettings['themes'][$themeName] = $userInput;
  325. }
  326. # handle images
  327. $images = $request->getUploadedFiles();
  328. if(!isset($_SESSION['errors']) && isset($images[$themeName]))
  329. {
  330. $userInput = $this->saveImages($imageFields, $userInput, $userSettings, $images[$themeName]);
  331. # set user input as theme settings
  332. $userSettings['themes'][$themeName] = $userInput;
  333. }
  334. /* check for errors and redirect to path, if errors found */
  335. if(isset($_SESSION['errors']))
  336. {
  337. $this->c->flash->addMessage('error', 'Please correct the errors');
  338. return $response->withRedirect($this->c->router->pathFor('themes.show'));
  339. }
  340. /* store updated settings */
  341. \Typemill\Settings::updateSettings($userSettings);
  342. $this->c->flash->addMessage('info', 'Settings are stored');
  343. return $response->withRedirect($this->c->router->pathFor('themes.show'));
  344. }
  345. }
  346. public function savePlugins($request, $response, $args)
  347. {
  348. if($request->isPost())
  349. {
  350. $referer = $request->getHeader('HTTP_REFERER');
  351. $uri = $request->getUri()->withUserInfo('');
  352. $base_url = $uri->getBaseUrl();
  353. /* security, users should not be able to fake post with settings from other typemill pages.
  354. if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/plugins' )
  355. {
  356. $this->c->flash->addMessage('error', 'illegal referer');
  357. return $response->withRedirect($this->c->router->pathFor('plugins.show'));
  358. }
  359. */
  360. $userSettings = \Typemill\Settings::getUserSettings();
  361. $pluginSettings = array();
  362. $userInput = $request->getParams();
  363. $validate = new Validation();
  364. /* use the stored user settings and iterate over all original plugin settings, so we do not forget any... */
  365. foreach($userSettings['plugins'] as $pluginName => $pluginUserSettings)
  366. {
  367. /* if there are no input-data for this plugin, then use the stored plugin settings */
  368. if(!isset($userInput[$pluginName]))
  369. {
  370. $pluginSettings[$pluginName] = $pluginUserSettings;
  371. }
  372. else
  373. {
  374. /* validate the user-input */
  375. $imageFields = $this->validateInput('plugins', $pluginName, $userInput[$pluginName], $validate);
  376. /* use the input data */
  377. $pluginSettings[$pluginName] = $userInput[$pluginName];
  378. }
  379. # handle images
  380. $images = $request->getUploadedFiles();
  381. if(!isset($_SESSION['errors']) && isset($images[$pluginName]))
  382. {
  383. $userInput[$pluginName] = $this->saveImages($imageFields, $userInput[$pluginName], $userSettings, $images[$pluginName]);
  384. # set user input as theme settings
  385. $pluginSettings[$pluginName] = $userInput[$pluginName];
  386. }
  387. /* deactivate the plugin, if there is no active flag */
  388. if(!isset($userInput[$pluginName]['active']))
  389. {
  390. $pluginSettings[$pluginName]['active'] = false;
  391. }
  392. }
  393. if(isset($_SESSION['errors']))
  394. {
  395. $this->c->flash->addMessage('error', 'Please correct the errors below');
  396. }
  397. else
  398. {
  399. /* if everything is valid, add plugin settings to base settings again */
  400. $userSettings['plugins'] = $pluginSettings;
  401. /* store updated settings */
  402. \Typemill\Settings::updateSettings($userSettings);
  403. $this->c->flash->addMessage('info', 'Settings are stored');
  404. }
  405. return $response->withRedirect($this->c->router->pathFor('plugins.show'));
  406. }
  407. }
  408. private function validateInput($objectType, $objectName, $userInput, $validate)
  409. {
  410. /* fetch the original settings from the folder (plugin or theme) to get the field definitions */
  411. $originalSettings = \Typemill\Settings::getObjectSettings($objectType, $objectName);
  412. # images get special treatment
  413. $imageFieldDefinitions = array();
  414. if(isset($originalSettings['forms']['fields']))
  415. {
  416. /* flaten the multi-dimensional array with fieldsets to a one-dimensional array */
  417. $originalFields = array();
  418. foreach($originalSettings['forms']['fields'] as $fieldName => $fieldValue)
  419. {
  420. if(isset($fieldValue['fields']))
  421. {
  422. foreach($fieldValue['fields'] as $subFieldName => $subFieldValue)
  423. {
  424. $originalFields[$subFieldName] = $subFieldValue;
  425. }
  426. }
  427. else
  428. {
  429. $originalFields[$fieldName] = $fieldValue;
  430. }
  431. }
  432. # if the plugin defines frontend fields
  433. if(isset($originalSettings['public']))
  434. {
  435. $originalFields['recaptcha'] = ['type' => 'checkbox', 'label' => 'Google Recaptcha', 'checkboxlabel' => 'Activate Recaptcha' ];
  436. $originalFields['recaptcha_webkey'] = ['type' => 'text', 'label' => 'Recaptcha Website Key', 'help' => 'Add the recaptcha website key here. You can get the key from the recaptcha website.', 'description' => 'The website key is mandatory if you activate the recaptcha field'];
  437. $originalFields['recaptcha_secretkey'] = ['type' => 'text', 'label' => 'Recaptcha Secret Key', 'help' => 'Add the recaptcha secret key here. You can get the key from the recaptcha website.', 'description' => 'The secret key is mandatory if you activate the recaptcha field'];
  438. }
  439. # if plugin is not active, then skip required
  440. $skiprequired = false;
  441. if($objectType == 'plugins' && !isset($userInput['active']))
  442. {
  443. $skiprequired = true;
  444. }
  445. /* take the user input data and iterate over all fields and values */
  446. foreach($userInput as $fieldName => $fieldValue)
  447. {
  448. /* get the corresponding field definition from original plugin settings */
  449. $fieldDefinition = isset($originalFields[$fieldName]) ? $originalFields[$fieldName] : false;
  450. if($fieldDefinition)
  451. {
  452. /* validate user input for this field */
  453. $validate->objectField($fieldName, $fieldValue, $objectName, $fieldDefinition, $skiprequired);
  454. if($fieldDefinition['type'] == 'image')
  455. {
  456. # we want to return all images-fields for further processing
  457. $imageFieldDefinitions[$fieldName] = $fieldDefinition;
  458. }
  459. }
  460. if(!$fieldDefinition && $fieldName != 'active')
  461. {
  462. $_SESSION['errors'][$objectName][$fieldName] = array('This field is not defined!');
  463. }
  464. }
  465. }
  466. return $imageFieldDefinitions;
  467. }
  468. protected function saveImages($imageFields, $userInput, $userSettings, $files)
  469. {
  470. # initiate image processor with standard image sizes
  471. $processImages = new ProcessImage($userSettings['images']);
  472. if(!$processImages->checkFolders())
  473. {
  474. $this->c->flash->addMessage('error', 'Please make sure that your media folder exists and is writable.');
  475. return false;
  476. }
  477. foreach($imageFields as $fieldName => $imageField)
  478. {
  479. if(isset($userInput[$fieldName]))
  480. {
  481. # handle single input with single file upload
  482. $image = $files[$fieldName];
  483. if($image->getError() === UPLOAD_ERR_OK)
  484. {
  485. # not the most elegant, but createImage expects a base64-encoded string.
  486. $imageContent = $image->getStream()->getContents();
  487. $imageData = base64_encode($imageContent);
  488. $imageSrc = 'data: ' . $image->getClientMediaType() . ';base64,' . $imageData;
  489. if($processImages->createImage($imageSrc, $image->getClientFilename(), $userSettings['images'], $overwrite = NULL))
  490. {
  491. # returns image path to media library
  492. $userInput[$fieldName] = $processImages->publishImage();
  493. }
  494. }
  495. }
  496. }
  497. return $userInput;
  498. }
  499. /***********************
  500. ** USER MANAGEMENT **
  501. ***********************/
  502. public function showUser($request, $response, $args)
  503. {
  504. if($_SESSION['role'] == 'editor' && $_SESSION['user'] !== $args['username'])
  505. {
  506. return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
  507. }
  508. $validate = new Validation();
  509. if($validate->username($args['username']))
  510. {
  511. $user = new User();
  512. $users = $user->getUsers();
  513. $userrole = $user->getUserroles();
  514. $userdata = $user->getUser($args['username']);
  515. $settings = $this->c->get('settings');
  516. if($userdata)
  517. {
  518. return $this->render($response, 'settings/user.twig', array('settings' => $settings, 'users' => $users, 'userdata' => $userdata, 'userrole' => $userrole, 'username' => $args['username'] ));
  519. }
  520. }
  521. $this->c->flash->addMessage('error', 'User does not exists');
  522. return $response->withRedirect($this->c->router->pathFor('user.list'));
  523. }
  524. public function listUser($request, $response)
  525. {
  526. $user = new User();
  527. $users = $user->getUsers();
  528. $userdata = array();
  529. $route = $request->getAttribute('route');
  530. $settings = $this->c->get('settings');
  531. foreach($users as $username)
  532. {
  533. $userdata[] = $user->getUser($username);
  534. }
  535. return $this->render($response, 'settings/userlist.twig', array('settings' => $settings, 'users' => $users, 'userdata' => $userdata, 'route' => $route->getName() ));
  536. }
  537. public function newUser($request, $response, $args)
  538. {
  539. $user = new User();
  540. $users = $user->getUsers();
  541. $userrole = $user->getUserroles();
  542. $route = $request->getAttribute('route');
  543. $settings = $this->c->get('settings');
  544. return $this->render($response, 'settings/usernew.twig', array('settings' => $settings, 'users' => $users, 'userrole' => $userrole, 'route' => $route->getName() ));
  545. }
  546. public function createUser($request, $response, $args)
  547. {
  548. if($request->isPost())
  549. {
  550. $referer = $request->getHeader('HTTP_REFERER');
  551. $uri = $request->getUri()->withUserInfo('');
  552. $base_url = $uri->getBaseUrl();
  553. /* security, users should not be able to fake post with settings from other typemill pages.
  554. if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/user/new' )
  555. {
  556. $this->c->flash->addMessage('error', 'illegal referer');
  557. return $response->withRedirect($this->c->router->pathFor('user.new'));
  558. }
  559. */
  560. $params = $request->getParams();
  561. $user = new User();
  562. $userroles = $user->getUserroles();
  563. $validate = new Validation();
  564. if($validate->newUser($params, $userroles))
  565. {
  566. $userdata = array('username' => $params['username'], 'firstname' => $params['firstname'], 'lastname' => $params['lastname'], 'email' => $params['email'], 'userrole' => $params['userrole'], 'password' => $params['password']);
  567. $user->createUser($userdata);
  568. $this->c->flash->addMessage('info', 'Welcome, there is a new user!');
  569. return $response->withRedirect($this->c->router->pathFor('user.list'));
  570. }
  571. $this->c->flash->addMessage('error', 'Please correct your input');
  572. return $response->withRedirect($this->c->router->pathFor('user.new'));
  573. }
  574. }
  575. public function updateUser($request, $response, $args)
  576. {
  577. if($request->isPost())
  578. {
  579. $referer = $request->getHeader('HTTP_REFERER');
  580. $uri = $request->getUri()->withUserInfo('');
  581. $base_url = $uri->getBaseUrl();
  582. /* security, users should not be able to fake post with settings from other typemill pages.
  583. if(!isset($referer[0]) OR strpos($referer[0], $base_url . '/tm/user/') === false )
  584. {
  585. $this->c->flash->addMessage('error', 'illegal referer');
  586. return $response->withRedirect($this->c->router->pathFor('user.list'));
  587. }
  588. */
  589. $params = $request->getParams();
  590. $user = new User();
  591. $userroles = $user->getUserroles();
  592. $validate = new Validation();
  593. /* non admins have different update rights */
  594. if($_SESSION['role'] !== 'administrator')
  595. {
  596. /* if an editor tries to update other userdata than its own */
  597. if($_SESSION['user'] !== $params['username'])
  598. {
  599. return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
  600. }
  601. /* non admins cannot change his userrole */
  602. $params['userrole'] = $_SESSION['role'];
  603. }
  604. if($validate->existingUser($params, $userroles))
  605. {
  606. $userdata = array('username' => $params['username'], 'firstname' => $params['firstname'], 'lastname' => $params['lastname'], 'email' => $params['email'], 'userrole' => $params['userrole']);
  607. if(empty($params['password']) AND empty($params['newpassword']))
  608. {
  609. $user->updateUser($userdata);
  610. $this->c->flash->addMessage('info', 'Saved all changes');
  611. return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
  612. }
  613. elseif($validate->newPassword($params))
  614. {
  615. $userdata['password'] = $params['newpassword'];
  616. $user->updateUser($userdata);
  617. $this->c->flash->addMessage('info', 'Saved all changes');
  618. return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
  619. }
  620. }
  621. $this->c->flash->addMessage('error', 'Please correct your input');
  622. return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
  623. }
  624. }
  625. public function deleteUser($request, $response, $args)
  626. {
  627. if($request->isPost())
  628. {
  629. $referer = $request->getHeader('HTTP_REFERER');
  630. $uri = $request->getUri()->withUserInfo('');
  631. $base_url = $uri->getBaseUrl();
  632. /* security, users should not be able to fake post with settings from other typemill pages.
  633. if(!isset($referer[0]) OR strpos($referer[0], $base_url . '/tm/user/') === false )
  634. {
  635. $this->c->flash->addMessage('error', 'illegal referer');
  636. return $response->withRedirect($this->c->router->pathFor('user.list'));
  637. }
  638. */
  639. $params = $request->getParams();
  640. $validate = new Validation();
  641. $user = new User();
  642. /* non admins have different update rights */
  643. if($_SESSION['role'] !== 'administrator')
  644. {
  645. /* if an editor tries to delete other user than its own */
  646. if($_SESSION['user'] !== $params['username'])
  647. {
  648. return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
  649. }
  650. }
  651. if($validate->username($params['username']))
  652. {
  653. $user->deleteUser($params['username']);
  654. # if user deleted his own account
  655. if($_SESSION['user'] == $params['username'])
  656. {
  657. session_destroy();
  658. return $response->withRedirect($this->c->router->pathFor('auth.show'));
  659. }
  660. $this->c->flash->addMessage('info', 'Say goodbye, the user is gone!');
  661. return $response->withRedirect($this->c->router->pathFor('user.list'));
  662. }
  663. $this->c->flash->addMessage('error', 'Ups, we did not find that user');
  664. return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
  665. }
  666. }
  667. private function getThemes()
  668. {
  669. $themeFolder = $this->c->get('settings')['rootPath'] . $this->c->get('settings')['themeFolder'];
  670. $themeFolderC = scandir($themeFolder);
  671. $themes = array();
  672. foreach ($themeFolderC as $key => $theme)
  673. {
  674. if (!in_array($theme, array(".","..")))
  675. {
  676. if (is_dir($themeFolder . DIRECTORY_SEPARATOR . $theme))
  677. {
  678. $themes[] = $theme;
  679. }
  680. }
  681. }
  682. return $themes;
  683. }
  684. private function getCopyright()
  685. {
  686. return array(
  687. "©",
  688. "CC-BY",
  689. "CC-BY-NC",
  690. "CC-BY-NC-ND",
  691. "CC-BY-NC-SA",
  692. "CC-BY-ND",
  693. "CC-BY-SA",
  694. "None"
  695. );
  696. }
  697. private function getLanguages()
  698. {
  699. return array(
  700. 'en' => 'English',
  701. 'ru' => 'Russian',
  702. 'nl' => 'Dutch, Flemish',
  703. 'de' => 'German',
  704. 'it' => 'Italian',
  705. 'fr' => 'French',
  706. );
  707. }
  708. }