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-2020 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 18use Abraham\TwitterOAuth\TwitterOAuth; 19use phpMyFAQ\Category; 20use phpMyFAQ\Changelog; 21use phpMyFAQ\Filter; 22use phpMyFAQ\Helper\LinkVerifierHelper; 23use phpMyFAQ\Instance\Elasticsearch; 24use phpMyFAQ\Link; 25use phpMyFAQ\Logging; 26use phpMyFAQ\Notification; 27use phpMyFAQ\Question; 28use phpMyFAQ\Services\Twitter; 29use phpMyFAQ\Strings; 30use phpMyFAQ\Tags; 31use phpMyFAQ\Visits; 32 33if (!defined('IS_VALID_PHPMYFAQ')) { 34 http_response_code(400); 35 exit(); 36} 37 38if ($user->perm->checkRight($user->getUserId(), 'edit_faq') || $user->perm->checkRight($user->getUserId(), 'add_faq')) { 39 40 // FAQ data 41 $dateStart = Filter::filterInput(INPUT_POST, 'dateStart', FILTER_SANITIZE_STRING); 42 $dateEnd = Filter::filterInput(INPUT_POST, 'dateEnd', FILTER_SANITIZE_STRING); 43 $question = Filter::filterInput(INPUT_POST, 'question', FILTER_SANITIZE_STRING); 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_SANITIZE_STRING); 54 $tags = Filter::filterInput(INPUT_POST, 'tags', FILTER_SANITIZE_STRING); 55 $active = Filter::filterInput(INPUT_POST, 'active', FILTER_SANITIZE_STRING); 56 $sticky = Filter::filterInput(INPUT_POST, 'sticky', FILTER_SANITIZE_STRING); 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_SANITIZE_STRING); 63 $author = Filter::filterInput(INPUT_POST, 'author', FILTER_SANITIZE_STRING); 64 $email = Filter::filterInput(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); 65 $comment = Filter::filterInput(INPUT_POST, 'comment', FILTER_SANITIZE_STRING); 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_SANITIZE_STRING); 70 $date = Filter::filterInput(INPUT_POST, 'date', FILTER_SANITIZE_STRING); 71 $notes = Filter::filterInput(INPUT_POST, 'notes', FILTER_SANITIZE_STRING); 72 73 // Permissions 74 $permissions = []; 75 if ('all' === Filter::filterInput(INPUT_POST, 'userpermission', FILTER_SANITIZE_STRING)) { 76 $permissions += [ 77 'restricted_user' => [ 78 -1, 79 ], 80 ]; 81 } else { 82 $permissions += [ 83 'restricted_user' => [ 84 Filter::filterInput(INPUT_POST, 'restricted_users', FILTER_VALIDATE_INT), 85 ], 86 ]; 87 } 88 89 if ('all' === Filter::filterInput(INPUT_POST, 'grouppermission', FILTER_SANITIZE_STRING)) { 90 $permissions += [ 91 'restricted_groups' => [ 92 -1, 93 ], 94 ]; 95 } else { 96 $permissions += Filter::filterInputArray( 97 INPUT_POST, 98 [ 99 'restricted_groups' => [ 100 'filter' => FILTER_VALIDATE_INT, 101 'flags' => FILTER_REQUIRE_ARRAY, 102 ], 103 ] 104 ); 105 } 106 107 if (!isset($categories['rubrik'])) { 108 $categories['rubrik'] = []; 109 } 110 111 if (!is_null($question) && !is_null($categories['rubrik'])) { 112 // new entry 113 $logging = new Logging($faqConfig); 114 $logging->logAdmin($user, 'admin-save-new-faq'); 115 printf( 116 '<header class="row"><div class="col-lg-12"><h2 class="page-header">%s</h2></div></header>', 117 $PMF_LANG['ad_entry_aor'] 118 ); 119 120 $category = new Category($faqConfig, [], false); 121 $category->setUser($currentAdminUser); 122 $category->setGroups($currentAdminGroups); 123 $tagging = new Tags($faqConfig); 124 125 $recordData = [ 126 'lang' => $recordLang, 127 'active' => $active, 128 'sticky' => (!is_null($sticky) ? 1 : 0), 129 'thema' => Filter::removeAttributes(html_entity_decode($question, ENT_QUOTES | ENT_HTML5, 'UTF-8')), 130 'content' => Filter::removeAttributes(html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8')), 131 'keywords' => $keywords, 132 'author' => $author, 133 'email' => $email, 134 'comment' => (!is_null($comment) ? 'y' : 'n'), 135 'date' => empty($date) ? date('YmdHis') : str_replace(['-', ':', ' '], '', $date), 136 'dateStart' => (empty($dateStart) ? '00000000000000' : str_replace('-', '', $dateStart) . '000000'), 137 'dateEnd' => (empty($dateEnd) ? '99991231235959' : str_replace('-', '', $dateEnd) . '235959'), 138 'linkState' => '', 139 'linkDateCheck' => 0, 140 'notes' => Filter::removeAttributes($notes) 141 ]; 142 143 // Add new record and get that ID 144 $recordId = $faq->addRecord($recordData); 145 146 if ($recordId) { 147 // Create ChangeLog entry 148 $changelog = new Changelog($faqConfig); 149 $changelog->addEntry($recordId, $user->getUserId(), nl2br($changed), $recordData['lang']); 150 // Create the visit entry 151 152 $visits = new Visits($faqConfig); 153 $visits->logViews($recordId); 154 155 // Insert the new category relations 156 $faq->addCategoryRelations($categories['rubrik'], $recordId, $recordData['lang']); 157 // Insert the tags 158 if ($tags != '') { 159 $tagging->saveTags($recordId, explode(',', trim($tags))); 160 } 161 162 // Add user permissions 163 $faq->addPermission('user', $recordId, $permissions['restricted_user']); 164 $category->addPermission('user', $categories['rubrik'], $permissions['restricted_user']); 165 // Add group permission 166 if ($faqConfig->get('security.permLevel') !== 'basic') { 167 $faq->addPermission('group', $recordId, $permissions['restricted_groups']); 168 $category->addPermission('group', $categories['rubrik'], $permissions['restricted_groups']); 169 } 170 171 // Open question answered 172 $questionObject = new Question($faqConfig); 173 $openQuestionId = Filter::filterInput(INPUT_POST, 'openQuestionId', FILTER_VALIDATE_INT); 174 if (0 !== $openQuestionId) { 175 if ($faqConfig->get('records.enableDeleteQuestion')) { // deletes question 176 $questionObject->deleteQuestion($openQuestionId); 177 } else { // adds this faq record id to the related open question 178 $questionObject->updateQuestionAnswer($openQuestionId, $recordId, $categories['rubrik'][0]); 179 } 180 181 $url = sprintf( 182 '%s?action=faq&cat=%d&id=%d&artlang=%s', 183 $faqConfig->getDefaultUrl(), 184 $categories['rubrik'][0], 185 $recordId, 186 $recordLang 187 ); 188 $oLink = new Link($url, $faqConfig); 189 190 // notify the user who added the question 191 $notifyEmail = Filter::filterInput(INPUT_POST, 'notifyEmail', FILTER_SANITIZE_EMAIL); 192 $notifyUser = Filter::filterInput(INPUT_POST, 'notifyUser', FILTER_SANITIZE_STRING); 193 194 $notification = new Notification($faqConfig); 195 $notification->sendOpenQuestionAnswered($notifyEmail, $notifyUser, $oLink->toString()); 196 } 197 198 // Call Link Verification 199 LinkVerifierHelper::linkOndemandJavascript($recordId, $recordData['lang']); 200 201 // If Elasticsearch is enabled, index new FAQ document 202 if ($faqConfig->get('search.enableElasticsearch')) { 203 $esInstance = new Elasticsearch($faqConfig); 204 $esInstance->index( 205 [ 206 'id' => $recordId, 207 'lang' => $recordLang, 208 'solution_id' => $solutionId, 209 'question' => $recordData['thema'], 210 'answer' => $recordData['content'], 211 'keywords' => $keywords, 212 'category_id' => $categories['rubrik'][0] 213 ] 214 ); 215 } 216 217 // Callback to Twitter if enabled 218 if ($faqConfig->get('socialnetworks.enableTwitterSupport')) { 219 220 $connection = new TwitterOAuth( 221 $faqConfig->get('socialnetworks.twitterConsumerKey'), 222 $faqConfig->get('socialnetworks.twitterConsumerSecret'), 223 $faqConfig->get('socialnetworks.twitterAccessTokenKey'), 224 $faqConfig->get('socialnetworks.twitterAccessTokenSecret') 225 ); 226 227 $link = sprintf( 228 'index.php?action=faq&cat=%d&id=%d&artlang=%s', 229 $categories['rubrik'][0], 230 $recordId, 231 $recordLang 232 ); 233 $oLink = new Link($faqConfig->getDefaultUrl() . $link, $faqConfig); 234 $oLink->itemTitle = $question; 235 $link = $oLink->toString(); 236 237 if ($connection) { 238 $twitter = new Twitter($connection); 239 $twitter->addPost($question, $tags, $link); 240 } 241 } 242 243 printf('<p class="alert alert-success">%s</p>', $PMF_LANG['ad_entry_savedsuc']); 244 ?> 245 <script> 246 (() => { 247 setTimeout(() => { 248 window.location = "index.php?action=editentry&id=<?= $recordId; 249 ?>&lang=<?= $recordData['lang'] ?>"; 250 }, 5000); 251 })(); 252 </script> 253 <?php 254 } else { 255 printf( 256 '<p class="alert alert-danger">%s</p>', 257 $PMF_LANG['ad_entry_savedfail'] . $faqConfig->getDb()->error() 258 ); 259 } 260 } else { 261 printf( 262 '<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>', 263 $PMF_LANG['ad_entry_aor'] 264 ); 265 printf( 266 '<p class="alert alert-danger">%s</p>', $PMF_LANG['ad_entryins_fail'] 267 ); 268 ?> 269 <form action="?action=editpreview" method="post"> 270 <input type="hidden" name="question" value="<?= Strings::htmlspecialchars($question) ?>"> 271 <input type="hidden" name="content" class="mceNoEditor" value="<?= Strings::htmlspecialchars($content) ?>"> 272 <input type="hidden" name="lang" value="<?= $recordLang ?>"> 273 <input type="hidden" name="keywords" value="<?= $keywords ?>"> 274 <input type="hidden" name="tags" value="<?= $tags ?>"> 275 <input type="hidden" name="author" value="<?= $author ?>"> 276 <input type="hidden" name="email" value="<?= $email ?>"> 277 <?php 278 if (is_array($categories['rubrik'])) { 279 foreach ($categories['rubrik'] as $key => $_categories) { 280 echo ' <input type="hidden" name="rubrik[' . $key . ']" value="' . $_categories . '" />'; 281 } 282 } 283 ?> 284 <input type="hidden" name="solution_id" value="<?= $solutionId ?>"> 285 <input type="hidden" name="revision" value="<?= $revisionId ?>"> 286 <input type="hidden" name="active" value="<?= $active ?>"> 287 <input type="hidden" name="changed" value="<?= $changed ?>"> 288 <input type="hidden" name="comment" value="<?= $comment ?>"> 289 <input type="hidden" name="dateStart" value="<?= $dateStart ?>"> 290 <input type="hidden" name="dateEnd" value="<?= $dateEnd ?>"> 291 <input type="hidden" name="userpermission" value="<?= $user_permission ?>"> 292 <input type="hidden" name="restricted_users" value="<?= $permissions['restricted_user'] ?>"> 293 <input type="hidden" name="grouppermission" value="<?= $group_permission ?>"> 294 <input type="hidden" name="restricted_group" value="<?= $permissions['restricted_groups'] ?>"> 295 <input type="hidden" name="date" value="<?= $date ?>"> 296 <input type="hidden" name="notes" value="<?= $notes ?>"> 297 <p class="text-center"> 298 <button class="btn btn-primary" type="submit" name="submit"> 299 <?= $PMF_LANG['ad_entry_back'] ?> 300 </button> 301 </p> 302 </form> 303 <?php 304 } 305} else { 306 echo $PMF_LANG['err_NotAuth']; 307} 308