PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/phpmyfaq/admin/record.add.php

http://github.com/thorsten/phpMyFAQ
PHP | 330 lines | 269 code | 31 blank | 30 comment | 26 complexity | c997e3756dbc499ebb8d05657bdea331 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /**
  3. * Adds a record in the database, handles the preview and checks for missing
  4. * category entries.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public License,
  7. * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  8. * obtain one at http://mozilla.org/MPL/2.0/.
  9. *
  10. * @package phpMyFAQ
  11. * @author Thorsten Rinne <thorsten@phpmyfaq.de>
  12. * @copyright 2003-2021 phpMyFAQ Team
  13. * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
  14. * @link https://www.phpmyfaq.de
  15. * @since 2003-02-23
  16. */
  17. use Abraham\TwitterOAuth\TwitterOAuth;
  18. use phpMyFAQ\Category;
  19. use phpMyFAQ\Category\CategoryPermission;
  20. use phpMyFAQ\Category\CategoryRelation;
  21. use phpMyFAQ\Changelog;
  22. use phpMyFAQ\Faq\FaqPermission;
  23. use phpMyFAQ\Filter;
  24. use phpMyFAQ\Helper\CategoryHelper;
  25. use phpMyFAQ\Helper\LinkVerifierHelper;
  26. use phpMyFAQ\Instance\Elasticsearch;
  27. use phpMyFAQ\Link;
  28. use phpMyFAQ\Logging;
  29. use phpMyFAQ\Notification;
  30. use phpMyFAQ\Question;
  31. use phpMyFAQ\Services\Twitter;
  32. use phpMyFAQ\Strings;
  33. use phpMyFAQ\Tags;
  34. use phpMyFAQ\Visits;
  35. if (!defined('IS_VALID_PHPMYFAQ')) {
  36. http_response_code(400);
  37. exit();
  38. }
  39. if ($user->perm->hasPermission($user->getUserId(), 'edit_faq') || $user->perm->hasPermission($user->getUserId(), 'add_faq')) {
  40. // FAQ data
  41. $dateStart = Filter::filterInput(INPUT_POST, 'dateStart', FILTER_UNSAFE_RAW);
  42. $dateEnd = Filter::filterInput(INPUT_POST, 'dateEnd', FILTER_UNSAFE_RAW);
  43. $question = Filter::filterInput(INPUT_POST, 'question', FILTER_UNSAFE_RAW);
  44. $categories = Filter::filterInputArray(
  45. INPUT_POST,
  46. [
  47. 'rubrik' => [
  48. 'filter' => FILTER_VALIDATE_INT,
  49. 'flags' => FILTER_REQUIRE_ARRAY,
  50. ],
  51. ]
  52. );
  53. $recordLang = Filter::filterInput(INPUT_POST, 'lang', FILTER_UNSAFE_RAW);
  54. $tags = Filter::filterInput(INPUT_POST, 'tags', FILTER_UNSAFE_RAW);
  55. $active = Filter::filterInput(INPUT_POST, 'active', FILTER_UNSAFE_RAW);
  56. $sticky = Filter::filterInput(INPUT_POST, 'sticky', FILTER_UNSAFE_RAW);
  57. if ($faqConfig->get('main.enableMarkdownEditor')) {
  58. $content = Filter::filterInput(INPUT_POST, 'answer', FILTER_UNSAFE_RAW);
  59. } else {
  60. $content = Filter::filterInput(INPUT_POST, 'answer', FILTER_SANITIZE_SPECIAL_CHARS);
  61. }
  62. $keywords = Filter::filterInput(INPUT_POST, 'keywords', FILTER_UNSAFE_RAW);
  63. $author = Filter::filterInput(INPUT_POST, 'author', FILTER_UNSAFE_RAW);
  64. $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  65. $comment = Filter::filterInput(INPUT_POST, 'comment', FILTER_UNSAFE_RAW);
  66. $recordId = Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT);
  67. $solutionId = Filter::filterInput(INPUT_POST, 'solution_id', FILTER_VALIDATE_INT);
  68. $revisionId = Filter::filterInput(INPUT_POST, 'revision_id', FILTER_VALIDATE_INT);
  69. $changed = Filter::filterInput(INPUT_POST, 'changed', FILTER_UNSAFE_RAW);
  70. $date = Filter::filterInput(INPUT_POST, 'date', FILTER_UNSAFE_RAW);
  71. $notes = Filter::filterInput(INPUT_POST, 'notes', FILTER_UNSAFE_RAW);
  72. // Permissions
  73. $permissions = [];
  74. if ('all' === Filter::filterInput(INPUT_POST, 'userpermission', FILTER_UNSAFE_RAW)) {
  75. $permissions += [
  76. 'restricted_user' => [
  77. -1,
  78. ],
  79. ];
  80. } else {
  81. $permissions += [
  82. 'restricted_user' => [
  83. Filter::filterInput(INPUT_POST, 'restricted_users', FILTER_VALIDATE_INT),
  84. ],
  85. ];
  86. }
  87. if ('all' === Filter::filterInput(INPUT_POST, 'grouppermission', FILTER_UNSAFE_RAW)) {
  88. $permissions += [
  89. 'restricted_groups' => [
  90. -1,
  91. ],
  92. ];
  93. } else {
  94. $permissions += Filter::filterInputArray(
  95. INPUT_POST,
  96. [
  97. 'restricted_groups' => [
  98. 'filter' => FILTER_VALIDATE_INT,
  99. 'flags' => FILTER_REQUIRE_ARRAY,
  100. ],
  101. ]
  102. );
  103. }
  104. if (!isset($categories['rubrik'])) {
  105. $categories['rubrik'] = [];
  106. }
  107. if (!is_null($question) && !is_null($categories['rubrik'])) {
  108. // new entry
  109. $logging = new Logging($faqConfig);
  110. $logging->logAdmin($user, 'admin-save-new-faq');
  111. printf(
  112. '<header class="row"><div class="col-lg-12"><h2 class="page-header">%s</h2></div></header>',
  113. $PMF_LANG['ad_entry_aor']
  114. );
  115. $category = new Category($faqConfig, [], false);
  116. $category->setUser($currentAdminUser);
  117. $category->setGroups($currentAdminGroups);
  118. $categoryPermission = new CategoryPermission($faqConfig);
  119. $faqPermission = new FaqPermission($faqConfig);
  120. $tagging = new Tags($faqConfig);
  121. $notification = new Notification($faqConfig);
  122. $recordData = [
  123. 'lang' => $recordLang,
  124. 'active' => $active,
  125. 'sticky' => (!is_null($sticky) ? 1 : 0),
  126. 'thema' => Filter::removeAttributes(html_entity_decode($question, ENT_QUOTES | ENT_HTML5, 'UTF-8')),
  127. 'content' => Filter::removeAttributes(html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8')),
  128. 'keywords' => $keywords,
  129. 'author' => $author,
  130. 'email' => $email,
  131. 'comment' => (!is_null($comment) ? 'y' : 'n'),
  132. 'date' => empty($date) ? date('YmdHis') : str_replace(['-', ':', ' '], '', $date),
  133. 'dateStart' => (empty($dateStart) ? '00000000000000' : str_replace('-', '', $dateStart) . '000000'),
  134. 'dateEnd' => (empty($dateEnd) ? '99991231235959' : str_replace('-', '', $dateEnd) . '235959'),
  135. 'linkState' => '',
  136. 'linkDateCheck' => 0,
  137. 'notes' => Filter::removeAttributes($notes)
  138. ];
  139. // Add new record and get that ID
  140. $recordId = $faq->addRecord($recordData);
  141. if ($recordId) {
  142. // Create ChangeLog entry
  143. $changelog = new Changelog($faqConfig);
  144. $changelog->addEntry($recordId, $user->getUserId(), nl2br($changed), $recordData['lang']);
  145. // Create the visit entry
  146. $visits = new Visits($faqConfig);
  147. $visits->logViews((int)$recordId);
  148. $categoryRelation = new CategoryRelation($faqConfig);
  149. $categoryRelation->add($categories['rubrik'], $recordId, $recordData['lang']);
  150. // Insert the tags
  151. if ($tags != '') {
  152. $tagging->saveTags($recordId, explode(',', trim($tags)));
  153. }
  154. // Add user permissions
  155. $faqPermission->add(FaqPermission::USER, $recordId, $permissions['restricted_user']);
  156. $categoryPermission->add(CategoryPermission::USER, $categories['rubrik'], $permissions['restricted_user']);
  157. // Add group permission
  158. if ($faqConfig->get('security.permLevel') !== 'basic') {
  159. $faqPermission->add(FaqPermission::GROUP, $recordId, $permissions['restricted_groups']);
  160. $categoryPermission->add(
  161. CategoryPermission::GROUP,
  162. $categories['rubrik'],
  163. $permissions['restricted_groups']
  164. );
  165. }
  166. // Open question answered
  167. $questionObject = new Question($faqConfig);
  168. $openQuestionId = Filter::filterInput(INPUT_POST, 'openQuestionId', FILTER_VALIDATE_INT);
  169. if (0 !== $openQuestionId) {
  170. if ($faqConfig->get('records.enableDeleteQuestion')) { // deletes question
  171. $questionObject->deleteQuestion($openQuestionId);
  172. } else { // adds this faq record id to the related open question
  173. $questionObject->updateQuestionAnswer($openQuestionId, $recordId, $categories['rubrik'][0]);
  174. }
  175. $url = sprintf(
  176. '%s?action=faq&cat=%d&id=%d&artlang=%s',
  177. $faqConfig->getDefaultUrl(),
  178. $categories['rubrik'][0],
  179. $recordId,
  180. $recordLang
  181. );
  182. $oLink = new Link($url, $faqConfig);
  183. // notify the user who added the question
  184. $notifyEmail = Filter::filterInput(INPUT_POST, 'notifyEmail', FILTER_SANITIZE_EMAIL);
  185. $notifyUser = Filter::filterInput(INPUT_POST, 'notifyUser', FILTER_UNSAFE_RAW);
  186. $notification->sendOpenQuestionAnswered($notifyEmail, $notifyUser, $oLink->toString());
  187. }
  188. // Let the admin and the category owners to be informed by email of this new entry
  189. $categoryHelper = new CategoryHelper();
  190. $categoryHelper
  191. ->setCategory($category)
  192. ->setConfiguration($faqConfig);
  193. $moderators = $categoryHelper->getModerators($categories['rubrik']);
  194. $notification->sendNewFaqAdded($moderators, $recordId, $recordLang);
  195. // Call Link Verification
  196. LinkVerifierHelper::linkOndemandJavascript($recordId, $recordData['lang']);
  197. // If Elasticsearch is enabled, index new FAQ document
  198. if ($faqConfig->get('search.enableElasticsearch')) {
  199. $esInstance = new Elasticsearch($faqConfig);
  200. $esInstance->index(
  201. [
  202. 'id' => $recordId,
  203. 'lang' => $recordLang,
  204. 'solution_id' => $solutionId,
  205. 'question' => $recordData['thema'],
  206. 'answer' => $recordData['content'],
  207. 'keywords' => $keywords,
  208. 'category_id' => $categories['rubrik'][0]
  209. ]
  210. );
  211. }
  212. // Callback to Twitter if enabled
  213. if ($faqConfig->get('socialnetworks.enableTwitterSupport')) {
  214. $connection = new TwitterOAuth(
  215. $faqConfig->get('socialnetworks.twitterConsumerKey'),
  216. $faqConfig->get('socialnetworks.twitterConsumerSecret'),
  217. $faqConfig->get('socialnetworks.twitterAccessTokenKey'),
  218. $faqConfig->get('socialnetworks.twitterAccessTokenSecret')
  219. );
  220. $link = sprintf(
  221. 'index.php?action=faq&amp;cat=%d&amp;id=%d&amp;artlang=%s',
  222. $categories['rubrik'][0],
  223. $recordId,
  224. $recordLang
  225. );
  226. $oLink = new Link($faqConfig->getDefaultUrl() . $link, $faqConfig);
  227. $oLink->itemTitle = $question;
  228. $link = $oLink->toString();
  229. if ($connection) {
  230. $twitter = new Twitter($connection);
  231. $twitter->addPost($question, $tags, $link);
  232. }
  233. }
  234. printf('<p class="alert alert-success">%s</p>', $PMF_LANG['ad_entry_savedsuc']);
  235. ?>
  236. <script>
  237. (() => {
  238. setTimeout(() => {
  239. window.location = "index.php?action=editentry&id=<?= $recordId;
  240. ?>&lang=<?= $recordData['lang'] ?>";
  241. }, 5000);
  242. })();
  243. </script>
  244. <?php
  245. } else {
  246. printf(
  247. '<p class="alert alert-danger">%s</p>',
  248. $PMF_LANG['ad_entry_savedfail'] . $faqConfig->getDb()->error()
  249. );
  250. }
  251. } else {
  252. printf(
  253. '<header class="row"><div class="col-lg-12"><h2 class="page-header"><i aria-hidden="true" class="fa fa-pencil"></i> %s</h2></div></header>',
  254. $PMF_LANG['ad_entry_aor']
  255. );
  256. printf(
  257. '<p class="alert alert-danger">%s</p>',
  258. $PMF_LANG['ad_entryins_fail']
  259. );
  260. ?>
  261. <form action="?action=editpreview" method="post">
  262. <input type="hidden" name="question" value="<?= Strings::htmlspecialchars($question) ?>">
  263. <input type="hidden" name="content" class="mceNoEditor" value="<?= Strings::htmlspecialchars($content) ?>">
  264. <input type="hidden" name="lang" value="<?= $recordLang ?>">
  265. <input type="hidden" name="keywords" value="<?= $keywords ?>">
  266. <input type="hidden" name="tags" value="<?= $tags ?>">
  267. <input type="hidden" name="author" value="<?= $author ?>">
  268. <input type="hidden" name="email" value="<?= $email ?>">
  269. <?php
  270. if (is_array($categories['rubrik'])) {
  271. foreach ($categories['rubrik'] as $key => $_categories) {
  272. echo ' <input type="hidden" name="rubrik[' . $key . ']" value="' . $_categories . '" />';
  273. }
  274. }
  275. ?>
  276. <input type="hidden" name="solution_id" value="<?= $solutionId ?>">
  277. <input type="hidden" name="revision" value="<?= $revisionId ?>">
  278. <input type="hidden" name="active" value="<?= $active ?>">
  279. <input type="hidden" name="changed" value="<?= $changed ?>">
  280. <input type="hidden" name="comment" value="<?= $comment ?>">
  281. <input type="hidden" name="dateStart" value="<?= $dateStart ?>">
  282. <input type="hidden" name="dateEnd" value="<?= $dateEnd ?>">
  283. <input type="hidden" name="userpermission" value="<?= $user_permission ?>">
  284. <input type="hidden" name="restricted_users" value="<?= $permissions['restricted_user'] ?>">
  285. <input type="hidden" name="grouppermission" value="<?= $group_permission ?>">
  286. <input type="hidden" name="restricted_group" value="<?= $permissions['restricted_groups'] ?>">
  287. <input type="hidden" name="date" value="<?= $date ?>">
  288. <input type="hidden" name="notes" value="<?= $notes ?>">
  289. <p class="text-center">
  290. <button class="btn btn-primary" type="submit" name="submit">
  291. <?= $PMF_LANG['ad_entry_back'] ?>
  292. </button>
  293. </p>
  294. </form>
  295. <?php
  296. }
  297. } else {
  298. echo $PMF_LANG['err_NotAuth'];
  299. }